2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2"}; //"0.93"}; // LordHavoc: disabled autoaim by default
24 cvar_t pr_zone_min_strings = {0, "pr_zone_min_strings", "64"};
26 mempool_t *pr_strings_mempool;
28 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
29 #define STRINGTEMP_BUFFERS 16
30 #define STRINGTEMP_LENGTH 4096
31 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
32 static int pr_string_tempindex = 0;
34 static char *PR_GetTempString(void)
37 s = pr_string_temp[pr_string_tempindex];
38 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
42 #define RETURN_EDICT(e) (G_INT(OFS_RETURN) = EDICT_TO_PROG(e))
43 #define PF_WARNING(s) do{Con_Printf(s);PR_PrintState();return;}while(0)
44 #define PF_ERROR(s) do{Host_Error(s);return;}while(0)
48 ===============================================================================
52 ===============================================================================
56 void PF_VarString(int first, char *out, int outlength)
62 outend = out + outlength - 1;
63 for (i = first;i < pr_argc && out < outend;i++)
65 s = G_STRING((OFS_PARM0+i*3));
66 while (out < outend && *s)
72 char *ENGINE_EXTENSIONS =
88 "DP_ENT_CUSTOMCOLORMAP "
89 "DP_ENT_EXTERIORMODELTOCLIENT "
91 "DP_ENT_LOWPRECISION "
94 "DP_GFX_EXTERNALTEXTURES "
96 "DP_GFX_QUAKE3MODELTAGS "
100 "DP_HALFLIFE_MAP_CVAR "
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 "
132 "DP_SND_DIRECTIONLESSATTNNONE "
139 "DP_SV_CLIENTCOLORS "
141 "DP_SV_DRAWONLYTOCLIENT "
144 "DP_SV_NODRAWTOCLIENT "
146 "DP_SV_PLAYERPHYSICS "
148 "DP_SV_ROTATINGBMODEL "
154 "DP_TE_EXPLOSIONRGB "
156 "DP_TE_PARTICLECUBE "
157 "DP_TE_PARTICLERAIN "
158 "DP_TE_PARTICLESNOW "
160 "DP_TE_QUADEFFECTS1 "
163 "DP_TE_STANDARDEFFECTBUILTINS "
166 "KRIMZON_SV_PARSECLIENTCOMMAND "
170 "PRYDON_CLIENTCURSOR "
171 "TENEBRAE_GFX_DLIGHTS "
175 qboolean checkextension(char *name)
180 for (e = ENGINE_EXTENSIONS;*e;e++)
187 while (*e && *e != ' ')
189 if (e - start == len)
190 if (!strncasecmp(start, name, len))
200 returns true if the extension is supported by the server
202 checkextension(extensionname)
205 void PF_checkextension (void)
207 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
214 This is a TERMINAL error, which will kill off the entire server.
223 char string[STRINGTEMP_LENGTH];
225 PF_VarString(0, string, sizeof(string));
226 Con_Printf("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
227 ed = PROG_TO_EDICT(pr_global_struct->self);
230 PF_ERROR("Program error");
237 Dumps out self, then an error message. The program is aborted and self is
238 removed, but the level can continue.
243 void PF_objerror (void)
246 char string[STRINGTEMP_LENGTH];
248 PF_VarString(0, string, sizeof(string));
249 Con_Printf("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
250 ed = PROG_TO_EDICT(pr_global_struct->self);
260 Writes new values for v_forward, v_up, and v_right based on angles
264 void PF_makevectors (void)
266 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
273 Writes new values for v_forward, v_up, and v_right based on the given forward vector
274 vectorvectors(vector, vector)
277 void PF_vectorvectors (void)
279 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
280 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
287 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.
289 setorigin (entity, origin)
292 void PF_setorigin (void)
297 e = G_EDICT(OFS_PARM0);
299 PF_WARNING("setorigin: can not modify world entity\n");
301 PF_WARNING("setorigin: can not modify free entity\n");
302 org = G_VECTOR(OFS_PARM1);
303 VectorCopy (org, e->v->origin);
304 SV_LinkEdict (e, false);
308 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
312 for (i=0 ; i<3 ; i++)
314 PF_ERROR("SetMinMaxSize: backwards mins/maxs\n");
316 // set derived values
317 VectorCopy (min, e->v->mins);
318 VectorCopy (max, e->v->maxs);
319 VectorSubtract (max, min, e->v->size);
321 SV_LinkEdict (e, false);
328 the size box is rotated by the current angle
329 LordHavoc: no it isn't...
331 setsize (entity, minvector, maxvector)
334 void PF_setsize (void)
339 e = G_EDICT(OFS_PARM0);
341 PF_WARNING("setsize: can not modify world entity\n");
343 PF_WARNING("setsize: can not modify free entity\n");
344 min = G_VECTOR(OFS_PARM1);
345 max = G_VECTOR(OFS_PARM2);
346 SetMinMaxSize (e, min, max, false);
354 setmodel(entity, model)
357 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
358 void PF_setmodel (void)
364 e = G_EDICT(OFS_PARM0);
366 PF_WARNING("setmodel: can not modify world entity\n");
368 PF_WARNING("setmodel: can not modify free entity\n");
369 i = SV_ModelIndex(G_STRING(OFS_PARM1), 1);
370 e->v->model = PR_SetString(sv.model_precache[i]);
371 e->v->modelindex = i;
377 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
378 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
380 SetMinMaxSize (e, quakemins, quakemaxs, true);
383 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
390 broadcast print to everyone on server
395 void PF_bprint (void)
397 char string[STRINGTEMP_LENGTH];
398 PF_VarString(0, string, sizeof(string));
399 SV_BroadcastPrint(string);
406 single print to a specific client
408 sprint(clientent, value)
411 void PF_sprint (void)
415 char string[STRINGTEMP_LENGTH];
417 entnum = G_EDICTNUM(OFS_PARM0);
419 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
421 Con_Print("tried to sprint to a non-client\n");
425 client = svs.clients + entnum-1;
426 PF_VarString(1, string, sizeof(string));
427 MSG_WriteChar(&client->message,svc_print);
428 MSG_WriteString(&client->message, string);
436 single print to a specific client
438 centerprint(clientent, value)
441 void PF_centerprint (void)
445 char string[STRINGTEMP_LENGTH];
447 entnum = G_EDICTNUM(OFS_PARM0);
449 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
451 Con_Print("tried to sprint to a non-client\n");
455 client = svs.clients + entnum-1;
456 PF_VarString(1, string, sizeof(string));
457 MSG_WriteChar(&client->message,svc_centerprint);
458 MSG_WriteString(&client->message, string);
466 vector normalize(vector)
469 void PF_normalize (void)
475 value1 = G_VECTOR(OFS_PARM0);
477 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
481 newvalue[0] = newvalue[1] = newvalue[2] = 0;
485 newvalue[0] = value1[0] * new;
486 newvalue[1] = value1[1] * new;
487 newvalue[2] = value1[2] * new;
490 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
505 value1 = G_VECTOR(OFS_PARM0);
507 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
510 G_FLOAT(OFS_RETURN) = new;
517 float vectoyaw(vector)
520 void PF_vectoyaw (void)
525 value1 = G_VECTOR(OFS_PARM0);
527 if (value1[1] == 0 && value1[0] == 0)
531 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
536 G_FLOAT(OFS_RETURN) = yaw;
544 vector vectoangles(vector)
547 void PF_vectoangles (void)
549 double value1[3], forward, yaw, pitch;
551 VectorCopy(G_VECTOR(OFS_PARM0), value1);
553 if (value1[1] == 0 && value1[0] == 0)
563 // LordHavoc: optimized a bit
566 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
570 else if (value1[1] > 0)
575 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
576 pitch = (atan2(value1[2], forward) * 180 / M_PI);
581 VectorSet(G_VECTOR(OFS_RETURN), pitch, yaw, 0);
588 Returns a number from 0<= num < 1
593 void PF_random (void)
595 G_FLOAT(OFS_RETURN) = lhrandom(0, 1);
602 particle(origin, color, count)
605 void PF_particle (void)
611 org = G_VECTOR(OFS_PARM0);
612 dir = G_VECTOR(OFS_PARM1);
613 color = G_FLOAT(OFS_PARM2);
614 count = G_FLOAT(OFS_PARM3);
615 SV_StartParticle (org, dir, color, count);
625 void PF_ambientsound (void)
629 float vol, attenuation;
632 pos = G_VECTOR (OFS_PARM0);
633 samp = G_STRING(OFS_PARM1);
634 vol = G_FLOAT(OFS_PARM2);
635 attenuation = G_FLOAT(OFS_PARM3);
637 // check to see if samp was properly precached
638 soundnum = SV_SoundIndex(samp, 1);
646 // add an svc_spawnambient command to the level signon packet
649 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
651 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
653 MSG_WriteVector(&sv.signon, pos, sv.protocol);
656 MSG_WriteShort (&sv.signon, soundnum);
658 MSG_WriteByte (&sv.signon, soundnum);
660 MSG_WriteByte (&sv.signon, vol*255);
661 MSG_WriteByte (&sv.signon, attenuation*64);
669 Each entity can have eight independant sound sources, like voice,
672 Channel 0 is an auto-allocate channel, the others override anything
673 already running on that entity/channel pair.
675 An attenuation of 0 will play full volume everywhere in the level.
676 Larger attenuations will drop off.
688 entity = G_EDICT(OFS_PARM0);
689 channel = G_FLOAT(OFS_PARM1);
690 sample = G_STRING(OFS_PARM2);
691 volume = G_FLOAT(OFS_PARM3) * 255;
692 attenuation = G_FLOAT(OFS_PARM4);
694 if (volume < 0 || volume > 255)
695 PF_WARNING("SV_StartSound: volume must be in range 0-1\n");
697 if (attenuation < 0 || attenuation > 4)
698 PF_WARNING("SV_StartSound: attenuation must be in range 0-4\n");
700 if (channel < 0 || channel > 7)
701 PF_WARNING("SV_StartSound: channel must be in range 0-7\n");
703 SV_StartSound (entity, channel, sample, volume, attenuation);
715 PF_ERROR("break: break statement\n");
722 Used for use tracing and shot targeting
723 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
724 if the tryents flag is set.
726 traceline (vector1, vector2, tryents)
729 void PF_traceline (void)
736 pr_xfunction->builtinsprofile += 30;
738 v1 = G_VECTOR(OFS_PARM0);
739 v2 = G_VECTOR(OFS_PARM1);
740 move = G_FLOAT(OFS_PARM2);
741 ent = G_EDICT(OFS_PARM3);
743 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, move, ent);
745 pr_global_struct->trace_allsolid = trace.allsolid;
746 pr_global_struct->trace_startsolid = trace.startsolid;
747 pr_global_struct->trace_fraction = trace.fraction;
748 pr_global_struct->trace_inwater = trace.inwater;
749 pr_global_struct->trace_inopen = trace.inopen;
750 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
751 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
752 pr_global_struct->trace_plane_dist = trace.plane.dist;
754 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
756 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
757 // FIXME: add trace_endcontents
765 Used for use tracing and shot targeting
766 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
767 if the tryents flag is set.
769 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
772 // LordHavoc: added this for my own use, VERY useful, similar to traceline
773 void PF_tracebox (void)
775 float *v1, *v2, *m1, *m2;
780 pr_xfunction->builtinsprofile += 30;
782 v1 = G_VECTOR(OFS_PARM0);
783 m1 = G_VECTOR(OFS_PARM1);
784 m2 = G_VECTOR(OFS_PARM2);
785 v2 = G_VECTOR(OFS_PARM3);
786 move = G_FLOAT(OFS_PARM4);
787 ent = G_EDICT(OFS_PARM5);
789 trace = SV_Move (v1, m1, m2, v2, move, ent);
791 pr_global_struct->trace_allsolid = trace.allsolid;
792 pr_global_struct->trace_startsolid = trace.startsolid;
793 pr_global_struct->trace_fraction = trace.fraction;
794 pr_global_struct->trace_inwater = trace.inwater;
795 pr_global_struct->trace_inopen = trace.inopen;
796 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
797 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
798 pr_global_struct->trace_plane_dist = trace.plane.dist;
800 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
802 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
805 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
806 void PF_TraceToss (void)
812 pr_xfunction->builtinsprofile += 600;
814 ent = G_EDICT(OFS_PARM0);
815 if (ent == sv.edicts)
816 PF_WARNING("tracetoss: can not use world entity\n");
817 ignore = G_EDICT(OFS_PARM1);
819 trace = SV_Trace_Toss (ent, ignore);
821 pr_global_struct->trace_allsolid = trace.allsolid;
822 pr_global_struct->trace_startsolid = trace.startsolid;
823 pr_global_struct->trace_fraction = trace.fraction;
824 pr_global_struct->trace_inwater = trace.inwater;
825 pr_global_struct->trace_inopen = trace.inopen;
826 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
827 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
828 pr_global_struct->trace_plane_dist = trace.plane.dist;
830 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
832 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
840 Returns true if the given entity can move to the given position from it's
841 current position by walking or rolling.
843 scalar checkpos (entity, vector)
846 void PF_checkpos (void)
850 //============================================================================
853 qbyte checkpvs[MAX_MAP_LEAFS/8];
855 int PF_newcheckclient (int check)
861 // cycle to the next one
863 check = bound(1, check, svs.maxclients);
864 if (check == svs.maxclients)
872 pr_xfunction->builtinsprofile++;
874 if (i == svs.maxclients+1)
876 // look up the client's edict
878 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
879 if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET)))
881 // found a valid client (possibly the same one again)
885 // get the PVS for the entity
886 VectorAdd(ent->v->origin, ent->v->view_ofs, org);
888 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
889 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
898 Returns a client (or object that has a client enemy) that would be a
901 If there is more than one valid option, they are cycled each frame
903 If (self.origin + self.viewofs) is not in the PVS of the current target,
904 it is not returned at all.
909 int c_invis, c_notvis;
910 void PF_checkclient (void)
915 // find a new check if on a new frame
916 if (sv.time - sv.lastchecktime >= 0.1)
918 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
919 sv.lastchecktime = sv.time;
922 // return check if it might be visible
923 ent = EDICT_NUM(sv.lastcheck);
924 if (ent->e->free || ent->v->health <= 0)
926 RETURN_EDICT(sv.edicts);
930 // if current entity can't possibly see the check entity, return 0
931 self = PROG_TO_EDICT(pr_global_struct->self);
932 VectorAdd(self->v->origin, self->v->view_ofs, view);
933 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
936 RETURN_EDICT(sv.edicts);
940 // might be able to see it
945 //============================================================================
952 Sends text over to the client's execution buffer
954 stuffcmd (clientent, value)
957 void PF_stuffcmd (void)
963 entnum = G_EDICTNUM(OFS_PARM0);
964 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
966 Con_Print("Can't stuffcmd to a non-client\n");
969 str = G_STRING(OFS_PARM1);
972 host_client = svs.clients + entnum-1;
973 Host_ClientCommands ("%s", str);
981 Sends text to server console
986 void PF_localcmd (void)
988 Cbuf_AddText(G_STRING(OFS_PARM0));
1000 G_FLOAT(OFS_RETURN) = Cvar_VariableValue(G_STRING(OFS_PARM0));
1010 void PF_cvar_set (void)
1012 Cvar_Set(G_STRING(OFS_PARM0), G_STRING(OFS_PARM1));
1019 Returns a chain of entities that have origins within a spherical area
1021 findradius (origin, radius)
1024 void PF_findradius (void)
1026 edict_t *ent, *chain;
1027 vec_t radius, radius2;
1028 vec3_t org, eorg, mins, maxs;
1031 edict_t *touchedicts[MAX_EDICTS];
1033 chain = (edict_t *)sv.edicts;
1035 VectorCopy(G_VECTOR(OFS_PARM0), org);
1036 radius = G_FLOAT(OFS_PARM1);
1037 radius2 = radius * radius;
1039 mins[0] = org[0] - radius;
1040 mins[1] = org[1] - radius;
1041 mins[2] = org[2] - radius;
1042 maxs[0] = org[0] + radius;
1043 maxs[1] = org[1] + radius;
1044 maxs[2] = org[2] + radius;
1045 numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
1046 if (numtouchedicts > MAX_EDICTS)
1048 // this never happens
1049 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
1050 numtouchedicts = MAX_EDICTS;
1052 for (i = 0;i < numtouchedicts;i++)
1054 ent = touchedicts[i];
1055 pr_xfunction->builtinsprofile++;
1056 // LordHavoc: compare against bounding box rather than center so it
1057 // doesn't miss large objects, and use DotProduct instead of Length
1058 // for a major speedup
1059 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1060 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1061 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1062 if (DotProduct(eorg, eorg) < radius2)
1064 ent->v->chain = EDICT_TO_PROG(chain);
1069 RETURN_EDICT(chain);
1078 void PF_dprint (void)
1080 char string[STRINGTEMP_LENGTH];
1081 if (developer.integer)
1083 PF_VarString(0, string, sizeof(string));
1092 v = G_FLOAT(OFS_PARM0);
1094 s = PR_GetTempString();
1095 if ((float)((int)v) == v)
1096 sprintf(s, "%i", (int)v);
1098 sprintf(s, "%f", v);
1099 G_INT(OFS_RETURN) = PR_SetString(s);
1105 v = G_FLOAT(OFS_PARM0);
1106 G_FLOAT(OFS_RETURN) = fabs(v);
1112 s = PR_GetTempString();
1113 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1114 G_INT(OFS_RETURN) = PR_SetString(s);
1120 s = PR_GetTempString();
1121 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1122 G_INT(OFS_RETURN) = PR_SetString(s);
1125 void PF_Spawn (void)
1128 pr_xfunction->builtinsprofile += 20;
1133 void PF_Remove (void)
1136 pr_xfunction->builtinsprofile += 20;
1138 ed = G_EDICT(OFS_PARM0);
1139 if (ed == sv.edicts)
1140 PF_WARNING("remove: tried to remove world\n");
1141 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1142 PF_WARNING("remove: tried to remove a client\n");
1143 // LordHavoc: not an error because id1 progs did this in some cases (killtarget removes entities, even if they are already removed in some cases...)
1144 if (ed->e->free && developer.integer)
1145 PF_WARNING("remove: tried to remove an entity that was already removed\n");
1150 // entity (entity start, .string field, string match) find = #5;
1158 e = G_EDICTNUM(OFS_PARM0);
1159 f = G_INT(OFS_PARM1);
1160 s = G_STRING(OFS_PARM2);
1163 RETURN_EDICT(sv.edicts);
1167 for (e++ ; e < sv.num_edicts ; e++)
1169 pr_xfunction->builtinsprofile++;
1183 RETURN_EDICT(sv.edicts);
1186 // LordHavoc: added this for searching float, int, and entity reference fields
1187 void PF_FindFloat (void)
1194 e = G_EDICTNUM(OFS_PARM0);
1195 f = G_INT(OFS_PARM1);
1196 s = G_FLOAT(OFS_PARM2);
1198 for (e++ ; e < sv.num_edicts ; e++)
1200 pr_xfunction->builtinsprofile++;
1204 if (E_FLOAT(ed,f) == s)
1211 RETURN_EDICT(sv.edicts);
1214 // chained search for strings in entity fields
1215 // entity(.string field, string match) findchain = #402;
1216 void PF_findchain (void)
1221 edict_t *ent, *chain;
1223 chain = (edict_t *)sv.edicts;
1225 f = G_INT(OFS_PARM0);
1226 s = G_STRING(OFS_PARM1);
1229 RETURN_EDICT(sv.edicts);
1233 ent = NEXT_EDICT(sv.edicts);
1234 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1236 pr_xfunction->builtinsprofile++;
1239 t = E_STRING(ent,f);
1245 ent->v->chain = EDICT_TO_PROG(chain);
1249 RETURN_EDICT(chain);
1252 // LordHavoc: chained search for float, int, and entity reference fields
1253 // entity(.string field, float match) findchainfloat = #403;
1254 void PF_findchainfloat (void)
1259 edict_t *ent, *chain;
1261 chain = (edict_t *)sv.edicts;
1263 f = G_INT(OFS_PARM0);
1264 s = G_FLOAT(OFS_PARM1);
1266 ent = NEXT_EDICT(sv.edicts);
1267 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1269 pr_xfunction->builtinsprofile++;
1272 if (E_FLOAT(ent,f) != s)
1275 ent->v->chain = EDICT_TO_PROG(chain);
1279 RETURN_EDICT(chain);
1282 // LordHavoc: search for flags in float fields
1283 void PF_findflags (void)
1290 e = G_EDICTNUM(OFS_PARM0);
1291 f = G_INT(OFS_PARM1);
1292 s = (int)G_FLOAT(OFS_PARM2);
1294 for (e++ ; e < sv.num_edicts ; e++)
1296 pr_xfunction->builtinsprofile++;
1300 if ((int)E_FLOAT(ed,f) & s)
1307 RETURN_EDICT(sv.edicts);
1310 // LordHavoc: chained search for flags in float fields
1311 void PF_findchainflags (void)
1316 edict_t *ent, *chain;
1318 chain = (edict_t *)sv.edicts;
1320 f = G_INT(OFS_PARM0);
1321 s = (int)G_FLOAT(OFS_PARM1);
1323 ent = NEXT_EDICT(sv.edicts);
1324 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1326 pr_xfunction->builtinsprofile++;
1329 if (!((int)E_FLOAT(ent,f) & s))
1332 ent->v->chain = EDICT_TO_PROG(chain);
1336 RETURN_EDICT(chain);
1339 void PR_CheckEmptyString (char *s)
1342 PF_ERROR("Bad string");
1345 void PF_precache_file (void)
1346 { // precache_file is only used to copy files with qcc, it does nothing
1347 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1351 void PF_precache_sound (void)
1353 SV_SoundIndex(G_STRING(OFS_PARM0), 2);
1354 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1357 void PF_precache_model (void)
1359 SV_ModelIndex(G_STRING(OFS_PARM0), 2);
1360 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1364 void PF_coredump (void)
1369 void PF_traceon (void)
1374 void PF_traceoff (void)
1379 void PF_eprint (void)
1381 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1388 float(float yaw, float dist) walkmove
1391 void PF_walkmove (void)
1399 // assume failure if it returns early
1400 G_FLOAT(OFS_RETURN) = 0;
1402 ent = PROG_TO_EDICT(pr_global_struct->self);
1403 if (ent == sv.edicts)
1404 PF_WARNING("walkmove: can not modify world entity\n");
1406 PF_WARNING("walkmove: can not modify free entity\n");
1407 yaw = G_FLOAT(OFS_PARM0);
1408 dist = G_FLOAT(OFS_PARM1);
1410 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1413 yaw = yaw*M_PI*2 / 360;
1415 move[0] = cos(yaw)*dist;
1416 move[1] = sin(yaw)*dist;
1419 // save program state, because SV_movestep may call other progs
1420 oldf = pr_xfunction;
1421 oldself = pr_global_struct->self;
1423 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1426 // restore program state
1427 pr_xfunction = oldf;
1428 pr_global_struct->self = oldself;
1438 void PF_droptofloor (void)
1444 // assume failure if it returns early
1445 G_FLOAT(OFS_RETURN) = 0;
1447 ent = PROG_TO_EDICT(pr_global_struct->self);
1448 if (ent == sv.edicts)
1449 PF_WARNING("droptofloor: can not modify world entity\n");
1451 PF_WARNING("droptofloor: can not modify free entity\n");
1453 VectorCopy (ent->v->origin, end);
1456 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1458 if (trace.fraction != 1)
1460 VectorCopy (trace.endpos, ent->v->origin);
1461 SV_LinkEdict (ent, false);
1462 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1463 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1464 G_FLOAT(OFS_RETURN) = 1;
1465 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1466 ent->e->suspendedinairflag = true;
1474 void(float style, string value) lightstyle
1477 void PF_lightstyle (void)
1484 style = G_FLOAT(OFS_PARM0);
1485 val = G_STRING(OFS_PARM1);
1487 // change the string in sv
1488 sv.lightstyles[style] = val;
1490 // send message to all clients on this server
1491 if (sv.state != ss_active)
1494 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1498 MSG_WriteChar (&client->message, svc_lightstyle);
1499 MSG_WriteChar (&client->message,style);
1500 MSG_WriteString (&client->message, val);
1508 f = G_FLOAT(OFS_PARM0);
1510 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1512 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1514 void PF_floor (void)
1516 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1520 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1529 void PF_checkbottom (void)
1531 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1539 void PF_pointcontents (void)
1541 G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1548 entity nextent(entity)
1551 void PF_nextent (void)
1556 i = G_EDICTNUM(OFS_PARM0);
1559 pr_xfunction->builtinsprofile++;
1561 if (i == sv.num_edicts)
1563 RETURN_EDICT(sv.edicts);
1579 Pick a vector for the player to shoot along
1580 vector aim(entity, missilespeed)
1585 edict_t *ent, *check, *bestent;
1586 vec3_t start, dir, end, bestdir;
1589 float dist, bestdist;
1592 // assume failure if it returns early
1593 VectorCopy(pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1594 // if sv_aim is so high it can't possibly accept anything, skip out early
1595 if (sv_aim.value >= 1)
1598 ent = G_EDICT(OFS_PARM0);
1599 if (ent == sv.edicts)
1600 PF_WARNING("aim: can not use world entity\n");
1602 PF_WARNING("aim: can not use free entity\n");
1603 speed = G_FLOAT(OFS_PARM1);
1605 VectorCopy (ent->v->origin, start);
1608 // try sending a trace straight
1609 VectorCopy (pr_global_struct->v_forward, dir);
1610 VectorMA (start, 2048, dir, end);
1611 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1612 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1613 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1615 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1620 // try all possible entities
1621 VectorCopy (dir, bestdir);
1622 bestdist = sv_aim.value;
1625 check = NEXT_EDICT(sv.edicts);
1626 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1628 pr_xfunction->builtinsprofile++;
1629 if (check->v->takedamage != DAMAGE_AIM)
1633 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1634 continue; // don't aim at teammate
1635 for (j=0 ; j<3 ; j++)
1636 end[j] = check->v->origin[j]
1637 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1638 VectorSubtract (end, start, dir);
1639 VectorNormalize (dir);
1640 dist = DotProduct (dir, pr_global_struct->v_forward);
1641 if (dist < bestdist)
1642 continue; // to far to turn
1643 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1644 if (tr.ent == check)
1645 { // can shoot at this one
1653 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1654 dist = DotProduct (dir, pr_global_struct->v_forward);
1655 VectorScale (pr_global_struct->v_forward, dist, end);
1657 VectorNormalize (end);
1658 VectorCopy (end, G_VECTOR(OFS_RETURN));
1662 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1670 This was a major timewaster in progs, so it was converted to C
1673 void PF_changeyaw (void)
1676 float ideal, current, move, speed;
1678 ent = PROG_TO_EDICT(pr_global_struct->self);
1679 if (ent == sv.edicts)
1680 PF_WARNING("changeyaw: can not modify world entity\n");
1682 PF_WARNING("changeyaw: can not modify free entity\n");
1683 current = ANGLEMOD(ent->v->angles[1]);
1684 ideal = ent->v->ideal_yaw;
1685 speed = ent->v->yaw_speed;
1687 if (current == ideal)
1689 move = ideal - current;
1690 if (ideal > current)
1711 ent->v->angles[1] = ANGLEMOD (current + move);
1719 void PF_changepitch (void)
1722 float ideal, current, move, speed;
1725 ent = G_EDICT(OFS_PARM0);
1726 if (ent == sv.edicts)
1727 PF_WARNING("changepitch: can not modify world entity\n");
1729 PF_WARNING("changepitch: can not modify free entity\n");
1730 current = ANGLEMOD( ent->v->angles[0] );
1731 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1732 ideal = val->_float;
1735 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1738 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1739 speed = val->_float;
1742 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1746 if (current == ideal)
1748 move = ideal - current;
1749 if (ideal > current)
1770 ent->v->angles[0] = ANGLEMOD (current + move);
1774 ===============================================================================
1778 ===============================================================================
1781 #define MSG_BROADCAST 0 // unreliable to all
1782 #define MSG_ONE 1 // reliable to one (msg_entity)
1783 #define MSG_ALL 2 // reliable to all
1784 #define MSG_INIT 3 // write to the init string
1786 sizebuf_t *WriteDest (void)
1792 dest = G_FLOAT(OFS_PARM0);
1796 return &sv.datagram;
1799 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1800 entnum = NUM_FOR_EDICT(ent);
1801 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1802 Host_Error("WriteDest: tried to write to non-client\n");
1803 return &svs.clients[entnum-1].message;
1806 return &sv.reliable_datagram;
1812 Host_Error("WriteDest: bad destination");
1819 void PF_WriteByte (void)
1821 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1824 void PF_WriteChar (void)
1826 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1829 void PF_WriteShort (void)
1831 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1834 void PF_WriteLong (void)
1836 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1839 void PF_WriteAngle (void)
1841 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1844 void PF_WriteCoord (void)
1846 MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1849 void PF_WriteString (void)
1851 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1855 void PF_WriteEntity (void)
1857 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1860 //=============================================================================
1862 void PF_makestatic (void)
1867 ent = G_EDICT(OFS_PARM0);
1868 if (ent == sv.edicts)
1869 PF_WARNING("makestatic: can not modify world entity\n");
1871 PF_WARNING("makestatic: can not modify free entity\n");
1874 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1879 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1880 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1881 MSG_WriteShort (&sv.signon, ent->v->frame);
1885 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1886 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1887 MSG_WriteByte (&sv.signon, ent->v->frame);
1890 MSG_WriteByte (&sv.signon, ent->v->colormap);
1891 MSG_WriteByte (&sv.signon, ent->v->skin);
1892 for (i=0 ; i<3 ; i++)
1894 MSG_WriteCoord(&sv.signon, ent->v->origin[i], sv.protocol);
1895 MSG_WriteAngle(&sv.signon, ent->v->angles[i], sv.protocol);
1898 // throw the entity away now
1902 //=============================================================================
1909 void PF_setspawnparms (void)
1915 ent = G_EDICT(OFS_PARM0);
1916 i = NUM_FOR_EDICT(ent);
1917 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1919 Con_Print("tried to setspawnparms on a non-client\n");
1923 // copy spawn parms out of the client_t
1924 client = svs.clients + i-1;
1925 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1926 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1934 void PF_changelevel (void)
1938 // make sure we don't issue two changelevels
1939 if (svs.changelevel_issued)
1941 svs.changelevel_issued = true;
1943 s = G_STRING(OFS_PARM0);
1944 Cbuf_AddText (va("changelevel %s\n",s));
1949 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1954 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1959 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1966 Returns a vector of length < 1
1971 void PF_randomvec (void)
1976 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1977 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1978 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1980 while (DotProduct(temp, temp) >= 1);
1981 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1988 Returns a color vector indicating the lighting at the requested point.
1990 (Internal Operation note: actually measures the light beneath the point, just like
1991 the model lighting on the client)
1996 void PF_GetLight (void)
1998 vec3_t ambientcolor, diffusecolor, diffusenormal;
2000 p = G_VECTOR(OFS_PARM0);
2001 VectorClear(ambientcolor);
2002 VectorClear(diffusecolor);
2003 VectorClear(diffusenormal);
2004 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
2005 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
2006 VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
2009 void PF_registercvar (void)
2012 name = G_STRING(OFS_PARM0);
2013 value = G_STRING(OFS_PARM1);
2014 G_FLOAT(OFS_RETURN) = 0;
2016 // first check to see if it has already been defined
2017 if (Cvar_FindVar (name))
2020 // check for overlap with a command
2021 if (Cmd_Exists (name))
2023 Con_Printf("PF_registercvar: %s is a command\n", name);
2027 Cvar_Get(name, value, 0);
2029 G_FLOAT(OFS_RETURN) = 1; // success
2036 returns the minimum of two supplied floats
2043 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2045 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2046 else if (pr_argc >= 3)
2049 float f = G_FLOAT(OFS_PARM0);
2050 for (i = 1;i < pr_argc;i++)
2051 if (G_FLOAT((OFS_PARM0+i*3)) < f)
2052 f = G_FLOAT((OFS_PARM0+i*3));
2053 G_FLOAT(OFS_RETURN) = f;
2057 G_FLOAT(OFS_RETURN) = 0;
2058 PF_WARNING("min: must supply at least 2 floats\n");
2066 returns the maximum of two supplied floats
2073 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2075 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2076 else if (pr_argc >= 3)
2079 float f = G_FLOAT(OFS_PARM0);
2080 for (i = 1;i < pr_argc;i++)
2081 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2082 f = G_FLOAT((OFS_PARM0+i*3));
2083 G_FLOAT(OFS_RETURN) = f;
2087 G_FLOAT(OFS_RETURN) = 0;
2088 PF_WARNING("max: must supply at least 2 floats\n");
2096 returns number bounded by supplied range
2098 min(min, value, max)
2101 void PF_bound (void)
2103 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2110 returns a raised to power b
2117 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2124 copies data from one entity to another
2126 copyentity(src, dst)
2129 void PF_copyentity (void)
2132 in = G_EDICT(OFS_PARM0);
2133 if (in == sv.edicts)
2134 PF_WARNING("copyentity: can not read world entity\n");
2136 PF_WARNING("copyentity: can not read free entity\n");
2137 out = G_EDICT(OFS_PARM1);
2138 if (out == sv.edicts)
2139 PF_WARNING("copyentity: can not modify world entity\n");
2141 PF_WARNING("copyentity: can not modify free entity\n");
2142 memcpy(out->v, in->v, progs->entityfields * 4);
2149 sets the color of a client and broadcasts the update to all connected clients
2151 setcolor(clientent, value)
2154 void PF_setcolor (void)
2160 entnum = G_EDICTNUM(OFS_PARM0);
2161 i = G_FLOAT(OFS_PARM1);
2163 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2165 Con_Print("tried to setcolor a non-client\n");
2169 client = svs.clients + entnum-1;
2172 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2174 client->edict->v->team = (i & 15) + 1;
2177 if (client->old_colors != client->colors)
2179 client->old_colors = client->colors;
2180 // send notification to all clients
2181 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2182 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
2183 MSG_WriteByte (&sv.reliable_datagram, client->colors);
2191 effect(origin, modelname, startframe, framecount, framerate)
2194 void PF_effect (void)
2198 s = G_STRING(OFS_PARM1);
2200 PF_WARNING("effect: no model specified\n");
2202 i = SV_ModelIndex(s, 1);
2204 PF_WARNING("effect: model not precached\n");
2205 SV_StartEffect(G_VECTOR(OFS_PARM0), i, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2208 void PF_te_blood (void)
2210 if (G_FLOAT(OFS_PARM2) < 1)
2212 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2213 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2215 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2216 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2217 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2219 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2220 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2221 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2223 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2226 void PF_te_bloodshower (void)
2228 if (G_FLOAT(OFS_PARM3) < 1)
2230 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2231 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2233 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2234 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2235 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2237 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2238 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2239 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2241 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM2), sv.protocol);
2243 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2246 void PF_te_explosionrgb (void)
2248 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2249 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2251 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2252 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2253 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2255 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2256 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2257 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2260 void PF_te_particlecube (void)
2262 if (G_FLOAT(OFS_PARM3) < 1)
2264 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2265 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2267 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2268 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2269 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2271 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2272 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2273 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2275 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2276 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2277 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2279 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2281 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2282 // gravity true/false
2283 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2285 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM6), sv.protocol);
2288 void PF_te_particlerain (void)
2290 if (G_FLOAT(OFS_PARM3) < 1)
2292 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2293 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2295 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2296 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2297 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2299 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2300 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2301 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2303 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2304 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2305 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2307 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2309 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2312 void PF_te_particlesnow (void)
2314 if (G_FLOAT(OFS_PARM3) < 1)
2316 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2317 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2319 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2320 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2321 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2323 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2324 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2325 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2327 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2328 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2329 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2331 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2333 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2336 void PF_te_spark (void)
2338 if (G_FLOAT(OFS_PARM2) < 1)
2340 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2341 MSG_WriteByte(&sv.datagram, TE_SPARK);
2343 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2344 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2345 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2347 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2348 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2349 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2351 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2354 void PF_te_gunshotquad (void)
2356 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2357 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2359 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2360 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2361 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2364 void PF_te_spikequad (void)
2366 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2367 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2369 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2370 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2371 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2374 void PF_te_superspikequad (void)
2376 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2377 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2379 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2380 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2381 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2384 void PF_te_explosionquad (void)
2386 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2387 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2389 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2390 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2391 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2394 void PF_te_smallflash (void)
2396 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2397 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2399 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2400 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2401 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2404 void PF_te_customflash (void)
2406 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2408 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2409 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2411 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2412 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2413 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2415 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2417 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2419 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2420 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2421 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2424 void PF_te_gunshot (void)
2426 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2427 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2429 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2430 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2431 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2434 void PF_te_spike (void)
2436 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2437 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2439 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2440 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2441 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2444 void PF_te_superspike (void)
2446 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2447 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2449 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2450 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2451 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2454 void PF_te_explosion (void)
2456 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2457 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2459 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2460 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2461 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2464 void PF_te_tarexplosion (void)
2466 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2467 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2469 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2470 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2471 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2474 void PF_te_wizspike (void)
2476 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2477 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2479 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2480 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2481 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2484 void PF_te_knightspike (void)
2486 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2487 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2489 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2490 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2491 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2494 void PF_te_lavasplash (void)
2496 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2497 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2499 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2500 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2501 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2504 void PF_te_teleport (void)
2506 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2507 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2509 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2510 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2511 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2514 void PF_te_explosion2 (void)
2516 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2517 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2519 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2520 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2521 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2523 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2524 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM2));
2527 void PF_te_lightning1 (void)
2529 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2530 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2532 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2534 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2535 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2536 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2538 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2539 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2540 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2543 void PF_te_lightning2 (void)
2545 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2546 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2548 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2550 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2551 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2552 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2554 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2555 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2556 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2559 void PF_te_lightning3 (void)
2561 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2562 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2564 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2566 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2567 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2568 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2570 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2571 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2572 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2575 void PF_te_beam (void)
2577 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2578 MSG_WriteByte(&sv.datagram, TE_BEAM);
2580 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2582 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2583 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2584 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2586 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2587 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2588 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2591 void PF_te_plasmaburn (void)
2593 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2594 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2595 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2596 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2597 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2600 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2603 vec3_t v1, clipplanenormal, normal;
2604 vec_t clipplanedist, clipdist;
2606 if (surf->flags & SURF_PLANEBACK)
2607 VectorNegate(surf->plane->normal, normal);
2609 VectorCopy(surf->plane->normal, normal);
2610 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2612 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2613 VectorNormalizeFast(v1);
2614 CrossProduct(v1, normal, clipplanenormal);
2615 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2616 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2619 clipdist = -clipdist;
2620 VectorMA(out, clipdist, clipplanenormal, out);
2625 static msurface_t *getsurface(edict_t *ed, int surfnum)
2629 if (!ed || ed->e->free)
2631 modelindex = ed->v->modelindex;
2632 if (modelindex < 1 || modelindex >= MAX_MODELS)
2634 model = sv.models[modelindex];
2635 if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2637 return model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2641 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2642 void PF_getsurfacenumpoints(void)
2645 // return 0 if no such surface
2646 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2648 G_FLOAT(OFS_RETURN) = 0;
2652 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2654 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2655 void PF_getsurfacepoint(void)
2660 VectorClear(G_VECTOR(OFS_RETURN));
2661 ed = G_EDICT(OFS_PARM0);
2662 if (!ed || ed->e->free)
2664 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2666 pointnum = G_FLOAT(OFS_PARM2);
2667 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2669 // FIXME: implement rotation/scaling
2670 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2672 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2673 void PF_getsurfacenormal(void)
2676 VectorClear(G_VECTOR(OFS_RETURN));
2677 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2679 // FIXME: implement rotation/scaling
2680 if (surf->flags & SURF_PLANEBACK)
2681 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2683 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2685 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2686 void PF_getsurfacetexture(void)
2689 G_INT(OFS_RETURN) = 0;
2690 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2692 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2694 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2695 void PF_getsurfacenearpoint(void)
2697 int surfnum, best, modelindex;
2699 vec_t dist, bestdist;
2704 G_FLOAT(OFS_RETURN) = -1;
2705 ed = G_EDICT(OFS_PARM0);
2706 point = G_VECTOR(OFS_PARM1);
2708 if (!ed || ed->e->free)
2710 modelindex = ed->v->modelindex;
2711 if (modelindex < 1 || modelindex >= MAX_MODELS)
2713 model = sv.models[modelindex];
2714 if (!model->brushq1.numsurfaces)
2717 // FIXME: implement rotation/scaling
2718 VectorSubtract(point, ed->v->origin, p);
2720 bestdist = 1000000000;
2721 for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2723 surf = model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2724 dist = PlaneDiff(p, surf->plane);
2726 if (dist < bestdist)
2728 clippointtosurface(surf, p, clipped);
2729 VectorSubtract(clipped, p, clipped);
2730 dist += DotProduct(clipped, clipped);
2731 if (dist < bestdist)
2738 G_FLOAT(OFS_RETURN) = best;
2740 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2741 void PF_getsurfaceclippedpoint(void)
2746 VectorClear(G_VECTOR(OFS_RETURN));
2747 ed = G_EDICT(OFS_PARM0);
2748 if (!ed || ed->e->free)
2750 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2752 // FIXME: implement rotation/scaling
2753 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2754 clippointtosurface(surf, p, out);
2755 // FIXME: implement rotation/scaling
2756 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2759 #define MAX_PRFILES 256
2761 qfile_t *pr_files[MAX_PRFILES];
2763 void PR_Files_Init(void)
2765 memset(pr_files, 0, sizeof(pr_files));
2768 void PR_Files_CloseAll(void)
2771 for (i = 0;i < MAX_PRFILES;i++)
2774 FS_Close(pr_files[i]);
2779 //float(string s) stof = #81; // get numerical value from a string
2782 char string[STRINGTEMP_LENGTH];
2783 PF_VarString(0, string, sizeof(string));
2784 G_FLOAT(OFS_RETURN) = atof(string);
2787 //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
2790 int filenum, mode, i;
2791 char *modestring, *filename;
2792 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2793 if (pr_files[filenum] == NULL)
2795 if (filenum >= MAX_PRFILES)
2797 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2798 G_FLOAT(OFS_RETURN) = -2;
2801 mode = G_FLOAT(OFS_PARM1);
2804 case 0: // FILE_READ
2807 case 1: // FILE_APPEND
2810 case 2: // FILE_WRITE
2814 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2815 G_FLOAT(OFS_RETURN) = -3;
2818 filename = G_STRING(OFS_PARM0);
2819 // control characters do not cause issues with any platforms I know of, but they are usually annoying to deal with
2820 // ../ is parent directory on many platforms
2821 // // is parent directory on Amiga
2822 // / at the beginning of a path is root on unix, and parent directory on Amiga
2823 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2824 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2825 for (i = 0;filename[i];i++)
2827 if (filename[i] < ' ' || (filename[i] == '/' && filename[i+1] == '/') || (filename[i] == '.' && filename[i+1] == '.') || filename[i] == ':' || filename[i] == '\\' || filename[0] == '/')
2829 Con_Printf("PF_fopen: dangerous/confusing/annoying/non-portable filename \"%s\" not allowed. (contains control characters or // or .. or : or \\ or begins with /)\n", filename);
2830 G_FLOAT(OFS_RETURN) = -4;
2834 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2836 if (pr_files[filenum] == NULL && modestring == "rb")
2837 pr_files[filenum] = FS_Open(filename, modestring, false);
2839 if (pr_files[filenum] == NULL)
2840 G_FLOAT(OFS_RETURN) = -1;
2842 G_FLOAT(OFS_RETURN) = filenum;
2845 //void(float fhandle) fclose = #111; // closes a file
2846 void PF_fclose(void)
2848 int filenum = G_FLOAT(OFS_PARM0);
2849 if (filenum < 0 || filenum >= MAX_PRFILES)
2851 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2854 if (pr_files[filenum] == NULL)
2856 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2859 FS_Close(pr_files[filenum]);
2860 pr_files[filenum] = NULL;
2863 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2867 static char string[STRINGTEMP_LENGTH];
2868 int filenum = G_FLOAT(OFS_PARM0);
2869 if (filenum < 0 || filenum >= MAX_PRFILES)
2871 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2874 if (pr_files[filenum] == NULL)
2876 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2882 c = FS_Getc(pr_files[filenum]);
2883 if (c == '\r' || c == '\n' || c < 0)
2885 if (end < STRINGTEMP_LENGTH - 1)
2889 // remove \n following \r
2891 c = FS_Getc(pr_files[filenum]);
2892 if (developer.integer)
2893 Con_Printf("fgets: %s\n", string);
2895 G_INT(OFS_RETURN) = PR_SetString(string);
2897 G_INT(OFS_RETURN) = 0;
2900 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2904 char string[STRINGTEMP_LENGTH];
2905 int filenum = G_FLOAT(OFS_PARM0);
2906 if (filenum < 0 || filenum >= MAX_PRFILES)
2908 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2911 if (pr_files[filenum] == NULL)
2913 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2916 PF_VarString(1, string, sizeof(string));
2917 if ((stringlength = strlen(string)))
2918 FS_Write(pr_files[filenum], string, stringlength);
2919 if (developer.integer)
2920 Con_Printf("fputs: %s\n", string);
2923 //float(string s) strlen = #114; // returns how many characters are in a string
2924 void PF_strlen(void)
2927 s = G_STRING(OFS_PARM0);
2929 G_FLOAT(OFS_RETURN) = strlen(s);
2931 G_FLOAT(OFS_RETURN) = 0;
2934 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2935 void PF_strcat(void)
2937 char *s = PR_GetTempString();
2938 PF_VarString(0, s, STRINGTEMP_LENGTH);
2939 G_INT(OFS_RETURN) = PR_SetString(s);
2942 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2943 void PF_substring(void)
2945 int i, start, length;
2946 char *s, *string = PR_GetTempString();
2947 s = G_STRING(OFS_PARM0);
2948 start = G_FLOAT(OFS_PARM1);
2949 length = G_FLOAT(OFS_PARM2);
2952 for (i = 0;i < start && *s;i++, s++);
2953 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2956 G_INT(OFS_RETURN) = PR_SetString(string);
2959 //vector(string s) stov = #117; // returns vector value from a string
2962 char string[STRINGTEMP_LENGTH];
2963 PF_VarString(0, string, sizeof(string));
2964 Math_atov(string, G_VECTOR(OFS_RETURN));
2967 //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)
2968 void PF_strzone(void)
2971 in = G_STRING(OFS_PARM0);
2972 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2974 G_INT(OFS_RETURN) = PR_SetString(out);
2977 //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!!!)
2978 void PF_strunzone(void)
2980 Mem_Free(G_STRING(OFS_PARM0));
2983 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2984 //this function originally written by KrimZon, made shorter by LordHavoc
2985 void PF_clientcommand (void)
2987 client_t *temp_client;
2990 //find client for this entity
2991 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2992 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2994 Con_Print("PF_clientcommand: entity is not a client\n");
2998 temp_client = host_client;
2999 host_client = svs.clients + i;
3000 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
3001 host_client = temp_client;
3004 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
3005 //this function originally written by KrimZon, made shorter by LordHavoc
3006 //20040203: rewritten by LordHavoc (no longer uses allocations)
3008 char *tokens[256], tokenbuf[4096];
3009 void PF_tokenize (void)
3013 p = G_STRING(OFS_PARM0);
3017 while(COM_ParseToken(&p, false))
3019 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3021 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3023 tokens[num_tokens++] = tokenbuf + pos;
3024 strcpy(tokenbuf + pos, com_token);
3025 pos += strlen(com_token) + 1;
3028 G_FLOAT(OFS_RETURN) = num_tokens;
3031 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3032 //this function originally written by KrimZon, made shorter by LordHavoc
3035 int token_num = G_FLOAT(OFS_PARM0);
3036 if (token_num >= 0 && token_num < num_tokens)
3037 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
3039 G_INT(OFS_RETURN) = PR_SetString("");
3042 //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)
3043 void PF_setattachment (void)
3045 edict_t *e = G_EDICT(OFS_PARM0);
3046 edict_t *tagentity = G_EDICT(OFS_PARM1);
3047 char *tagname = G_STRING(OFS_PARM2);
3053 PF_WARNING("setattachment: can not modify world entity\n");
3055 PF_WARNING("setattachment: can not modify free entity\n");
3057 if (tagentity == NULL)
3058 tagentity = sv.edicts;
3060 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3062 v->edict = EDICT_TO_PROG(tagentity);
3064 v = GETEDICTFIELDVALUE(e, eval_tag_index);
3067 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3069 modelindex = (int)tagentity->v->modelindex;
3070 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3072 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3073 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3074 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3076 // FIXME: use a model function to get tag info (need to handle skeletal)
3077 if (v->_float == 0 && model->alias.aliasnum_tags)
3078 for (i = 0;i < model->alias.aliasnum_tags;i++)
3079 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3082 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);
3085 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));
3089 /////////////////////////////////////////
3090 // DP_MD3_TAGINFO extension coded by VorteX
3092 int SV_GetTagIndex (edict_t *e, char *tagname)
3097 i = e->v->modelindex;
3098 if (i < 1 || i >= MAX_MODELS)
3100 model = sv.models[i];
3103 if (model->data_overridetagnamesforskin && (unsigned int)e->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames)
3105 for (i = 0; i < model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames; i++)
3107 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)e->v->skin].data_overridetagnames[i].name))
3116 for (i = 0;i < model->alias.aliasnum_tags; i++)
3118 if (!(strcmp(tagname, model->alias.aliasdata_tags[i].name)))
3125 return tagindex + 1;
3128 // Warnings/errors code:
3129 // 0 - normal (everything all-right)
3132 // 3 - null or non-precached model
3133 // 4 - no tags with requested index
3134 // 5 - runaway loop at attachment chain
3135 extern cvar_t cl_bob;
3136 extern cvar_t cl_bobcycle;
3137 extern cvar_t cl_bobup;
3138 int SV_GetTagMatrix (matrix4x4_t *out, edict_t *ent, int tagindex)
3141 int modelindex, reqtag, reqframe, attachloop;
3142 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
3146 Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
3148 if (ent == sv.edicts)
3153 modelindex = (int)ent->v->modelindex;
3154 if (modelindex <= 0 || modelindex > MAX_MODELS)
3157 model = sv.models[modelindex];
3158 reqtag = model->alias.aliasnum_tags;
3160 if (tagindex <= 0 || tagindex > reqtag)
3162 if (reqtag && tagindex) // Only appear if model has no tags or not-null tag requested
3167 if (ent->v->frame < 0 || ent->v->frame > model->alias.aliasnum_tagframes)
3168 reqframe = model->numframes - 1; // if model has wrong frame, engine automatically switches to model last frame
3170 reqframe = ent->v->frame;
3172 // get initial tag matrix
3175 reqtag = (tagindex - 1) + ent->v->frame*model->alias.aliasnum_tags;
3176 Matrix4x4_Copy(&tagmatrix, &model->alias.aliasdata_tags[reqtag].matrix);
3179 Matrix4x4_CreateIdentity(&tagmatrix);
3181 if ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict)
3182 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
3186 attachent = EDICT_NUM(val->edict); // to this it entity our entity is attached
3187 val = GETEDICTFIELDVALUE(ent, eval_tag_index);
3188 Matrix4x4_CreateIdentity(&attachmatrix);
3189 if (val->_float >= 1 && attachent->v->modelindex >= 1 && attachent->v->modelindex < MAX_MODELS)
3191 model = sv.models[(int)attachent->v->modelindex];
3192 if (val->_float < model->alias.aliasnum_tags)
3194 // got tagname on parent entity attachment tag via tag_index (and got it's matrix)
3195 model = sv.models[(int)attachent->v->modelindex];
3196 reqtag = (val->_float - 1) + attachent->v->frame*model->alias.aliasnum_tags;
3197 Matrix4x4_Copy(&attachmatrix, &model->alias.aliasdata_tags[reqtag].matrix);
3201 // apply transformation by child entity matrix
3202 val = GETEDICTFIELDVALUE(ent, eval_scale);
3203 if (val->_float == 0)
3205 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);
3206 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3207 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]);
3208 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]);
3209 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]);
3210 Matrix4x4_Copy(&tagmatrix, out);
3212 // finally transformate by matrix of tag on parent entity
3213 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
3214 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];
3215 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];
3216 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];
3217 Matrix4x4_Copy(&tagmatrix, out);
3221 if (attachloop > 255) // prevent runaway looping
3224 while ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
3227 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
3228 val = GETEDICTFIELDVALUE(ent, eval_scale);
3229 if (val->_float == 0)
3231 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
3232 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);
3233 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3234 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]);
3235 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]);
3236 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]);
3238 if ((val = GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
3239 {// RENDER_VIEWMODEL magic
3240 Matrix4x4_Copy(&tagmatrix, out);
3241 ent = EDICT_NUM(val->edict);
3243 val = GETEDICTFIELDVALUE(ent, eval_scale);
3244 if (val->_float == 0)
3247 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);
3248 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3249 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]);
3250 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]);
3251 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]);
3254 // Cl_bob, ported from rendering code
3255 if (ent->v->health > 0 && cl_bob.value && cl_bobcycle.value)
3258 // LordHavoc: this code is *weird*, but not replacable (I think it
3259 // should be done in QC on the server, but oh well, quake is quake)
3260 // LordHavoc: figured out bobup: the time at which the sin is at 180
3261 // degrees (which allows lengthening or squishing the peak or valley)
3262 cycle = sv.time/cl_bobcycle.value;
3263 cycle -= (int)cycle;
3264 if (cycle < cl_bobup.value)
3265 cycle = sin(M_PI * cycle / cl_bobup.value);
3267 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
3268 // bob is proportional to velocity in the xy plane
3269 // (don't count Z, or jumping messes it up)
3270 bob = sqrt(ent->v->velocity[0]*ent->v->velocity[0] + ent->v->velocity[1]*ent->v->velocity[1])*cl_bob.value;
3271 bob = bob*0.3 + bob*0.7*cycle;
3272 out->m[2][3] += bound(-7, bob, 4);
3279 //float(entity ent, string tagname) gettagindex;
3281 void PF_gettagindex (void)
3283 edict_t *ent = G_EDICT(OFS_PARM0);
3284 char *tag_name = G_STRING(OFS_PARM1);
3285 int modelindex, tag_index;
3287 if (ent == sv.edicts)
3288 PF_WARNING("gettagindex: can't affect world entity\n");
3290 PF_WARNING("gettagindex: can't affect free entity\n");
3292 modelindex = (int)ent->v->modelindex;
3294 if (modelindex <= 0 || modelindex > MAX_MODELS)
3295 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(ent));
3298 tag_index = SV_GetTagIndex(ent, tag_name);
3300 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", NUM_FOR_EDICT(ent), tag_name);
3302 G_FLOAT(OFS_RETURN) = tag_index;
3305 //vector(entity ent, float tagindex) gettaginfo;
3306 void PF_gettaginfo (void)
3308 edict_t *e = G_EDICT(OFS_PARM0);
3309 int tagindex = (int)G_FLOAT(OFS_PARM1);
3310 matrix4x4_t tag_matrix;
3313 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
3314 Matrix4x4_ToVectors(&tag_matrix, pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up, G_VECTOR(OFS_RETURN));
3319 PF_WARNING("gettagindex: can't affect world entity\n");
3322 PF_WARNING("gettagindex: can't affect free entity\n");
3325 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3328 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", NUM_FOR_EDICT(e), tagindex);
3331 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", NUM_FOR_EDICT(e));
3337 /////////////////////////////////////////
3338 // DP_QC_FS_SEARCH extension
3340 // qc fs search handling
3341 #define MAX_SEARCHES 128
3343 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3345 void PR_Search_Init(void)
3347 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3350 void PR_Search_Reset(void)
3353 // reset the fssearch list
3354 for(i = 0; i < MAX_SEARCHES; i++)
3355 if(pr_fssearchlist[i])
3356 FS_FreeSearch(pr_fssearchlist[i]);
3357 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3364 float search_begin(string pattern, float caseinsensitive, float quiet)
3367 void PF_search_begin(void)
3371 int caseinsens, quiet;
3373 pattern = G_STRING(OFS_PARM0);
3375 PR_CheckEmptyString(pattern);
3377 caseinsens = G_FLOAT(OFS_PARM1);
3378 quiet = G_FLOAT(OFS_PARM2);
3380 for(handle = 0; handle < MAX_SEARCHES; handle++)
3381 if(!pr_fssearchlist[handle])
3384 if(handle >= MAX_SEARCHES)
3386 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3387 G_FLOAT(OFS_RETURN) = -2;
3391 if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3392 G_FLOAT(OFS_RETURN) = -1;
3394 G_FLOAT(OFS_RETURN) = handle;
3401 void search_end(float handle)
3404 void PF_search_end(void)
3408 handle = G_FLOAT(OFS_PARM0);
3410 if(handle < 0 || handle >= MAX_SEARCHES)
3412 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3415 if(pr_fssearchlist[handle] == NULL)
3417 Con_Printf("PF_search_end: no such handle %i\n", handle);
3421 FS_FreeSearch(pr_fssearchlist[handle]);
3422 pr_fssearchlist[handle] = NULL;
3429 float search_getsize(float handle)
3432 void PF_search_getsize(void)
3436 handle = G_FLOAT(OFS_PARM0);
3438 if(handle < 0 || handle >= MAX_SEARCHES)
3440 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3443 if(pr_fssearchlist[handle] == NULL)
3445 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3449 G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3454 VM_search_getfilename
3456 string search_getfilename(float handle, float num)
3459 void PF_search_getfilename(void)
3461 int handle, filenum;
3464 handle = G_FLOAT(OFS_PARM0);
3465 filenum = G_FLOAT(OFS_PARM1);
3467 if(handle < 0 || handle >= MAX_SEARCHES)
3469 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3472 if(pr_fssearchlist[handle] == NULL)
3474 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3477 if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3479 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3483 tmp = PR_GetTempString();
3484 strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3486 G_INT(OFS_RETURN) = PR_SetString(tmp);
3489 void PF_cvar_string (void)
3495 str = G_STRING(OFS_PARM0);
3496 var = Cvar_FindVar (str);
3499 tmp = PR_GetTempString();
3500 strcpy(tmp, var->string);
3504 G_INT(OFS_RETURN) = PR_SetString(tmp);
3507 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
3508 void PF_dropclient (void)
3511 client_t *oldhostclient;
3512 clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3513 if (clientnum < 0 || clientnum >= svs.maxclients)
3514 PF_WARNING("dropclient: not a client\n");
3515 if (!svs.clients[clientnum].active)
3516 PF_WARNING("dropclient: that client slot is not connected\n");
3517 oldhostclient = host_client;
3518 host_client = svs.clients + clientnum;
3519 SV_DropClient(false);
3520 host_client = oldhostclient;
3523 //entity() spawnclient (DP_SV_BOTCLIENT)
3524 void PF_spawnclient (void)
3528 pr_xfunction->builtinsprofile += 2;
3530 for (i = 0;i < svs.maxclients;i++)
3532 if (!svs.clients[i].active)
3534 pr_xfunction->builtinsprofile += 100;
3535 SV_ConnectClient (i, NULL);
3536 ed = EDICT_NUM(i + 1);
3543 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
3544 void PF_clienttype (void)
3547 clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3548 if (clientnum < 0 || clientnum >= svs.maxclients)
3549 G_FLOAT(OFS_RETURN) = 3;
3550 else if (!svs.clients[clientnum].active)
3551 G_FLOAT(OFS_RETURN) = 0;
3552 else if (svs.clients[clientnum].netconnection)
3553 G_FLOAT(OFS_RETURN) = 1;
3555 G_FLOAT(OFS_RETURN) = 2;
3558 builtin_t pr_builtin[] =
3561 PF_makevectors, // #1 void(entity e) makevectors
3562 PF_setorigin, // #2 void(entity e, vector o) setorigin
3563 PF_setmodel, // #3 void(entity e, string m) setmodel
3564 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
3565 NULL, // #5 void(entity e, vector min, vector max) setabssize
3566 PF_break, // #6 void() break
3567 PF_random, // #7 float() random
3568 PF_sound, // #8 void(entity e, float chan, string samp) sound
3569 PF_normalize, // #9 vector(vector v) normalize
3570 PF_error, // #10 void(string e) error
3571 PF_objerror, // #11 void(string e) objerror
3572 PF_vlen, // #12 float(vector v) vlen
3573 PF_vectoyaw, // #13 float(vector v) vectoyaw
3574 PF_Spawn, // #14 entity() spawn
3575 PF_Remove, // #15 void(entity e) remove
3576 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3577 PF_checkclient, // #17 entity() clientlist
3578 PF_Find, // #18 entity(entity start, .string fld, string match) find
3579 PF_precache_sound, // #19 void(string s) precache_sound
3580 PF_precache_model, // #20 void(string s) precache_model
3581 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3582 PF_findradius, // #22 entity(vector org, float rad) findradius
3583 PF_bprint, // #23 void(string s) bprint
3584 PF_sprint, // #24 void(entity client, string s) sprint
3585 PF_dprint, // #25 void(string s) dprint
3586 PF_ftos, // #26 void(string s) ftos
3587 PF_vtos, // #27 void(string s) vtos
3588 PF_coredump, // #28 void() coredump
3589 PF_traceon, // #29 void() traceon
3590 PF_traceoff, // #30 void() traceoff
3591 PF_eprint, // #31 void(entity e) eprint
3592 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3594 PF_droptofloor, // #34 float() droptofloor
3595 PF_lightstyle, // #35 void(float style, string value) lightstyle
3596 PF_rint, // #36 float(float v) rint
3597 PF_floor, // #37 float(float v) floor
3598 PF_ceil, // #38 float(float v) ceil
3600 PF_checkbottom, // #40 float(entity e) checkbottom
3601 PF_pointcontents, // #41 float(vector v) pointcontents
3603 PF_fabs, // #43 float(float f) fabs
3604 PF_aim, // #44 vector(entity e, float speed) aim
3605 PF_cvar, // #45 float(string s) cvar
3606 PF_localcmd, // #46 void(string s) localcmd
3607 PF_nextent, // #47 entity(entity e) nextent
3608 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3609 PF_changeyaw, // #49 void() ChangeYaw
3611 PF_vectoangles, // #51 vector(vector v) vectoangles
3612 PF_WriteByte, // #52 void(float to, float f) WriteByte
3613 PF_WriteChar, // #53 void(float to, float f) WriteChar
3614 PF_WriteShort, // #54 void(float to, float f) WriteShort
3615 PF_WriteLong, // #55 void(float to, float f) WriteLong
3616 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3617 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3618 PF_WriteString, // #58 void(float to, string s) WriteString
3619 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3620 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3621 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3622 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3623 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3624 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3625 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3627 SV_MoveToGoal, // #67 void(float step) movetogoal
3628 PF_precache_file, // #68 string(string s) precache_file
3629 PF_makestatic, // #69 void(entity e) makestatic
3630 PF_changelevel, // #70 void(string s) changelevel
3632 PF_cvar_set, // #72 void(string var, string val) cvar_set
3633 PF_centerprint, // #73 void(entity client, strings) centerprint
3634 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3635 PF_precache_model, // #75 string(string s) precache_model2
3636 PF_precache_sound, // #76 string(string s) precache_sound2
3637 PF_precache_file, // #77 string(string s) precache_file2
3638 PF_setspawnparms, // #78 void(entity e) setspawnparms
3641 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3650 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3651 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3652 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3653 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3654 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3655 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3656 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3657 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3658 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3659 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3670 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3671 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3672 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3673 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3674 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3675 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3676 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3677 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3678 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3679 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3680 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3681 a a a a a a a a // #120-199
3682 a a a a a a a a a a // #200-299
3683 a a a a a a a a a a // #300-399
3684 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3685 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3686 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3687 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3688 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3689 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3690 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3691 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3692 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3693 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3694 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3695 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3696 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3697 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3698 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3699 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3700 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3701 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3702 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3703 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3704 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3705 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3706 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3707 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3708 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3709 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3710 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3711 PF_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3712 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3713 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3714 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3715 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3716 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3717 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3718 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3719 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3720 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3721 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3722 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3723 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3724 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3725 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3726 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3727 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3728 PF_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3729 PF_search_end, // #445 void(float handle) search_end (DP_FS_SEARCH)
3730 PF_search_getsize, // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3731 PF_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3732 PF_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3733 PF_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3734 PF_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3735 PF_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3736 PF_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3737 PF_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3738 PF_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3739 PF_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3744 a a a a // #460-499 (LordHavoc)
3747 builtin_t *pr_builtins = pr_builtin;
3748 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3750 void PR_Cmd_Init(void)
3752 pr_strings_mempool = Mem_AllocPool("pr_stringszone", 0, NULL);
3757 void PR_Cmd_Reset(void)
3759 Mem_EmptyPool(pr_strings_mempool);
3761 PR_Files_CloseAll();