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 "
173 "NEXUIZ_PLAYERMODEL "
177 qboolean checkextension(char *name)
182 for (e = ENGINE_EXTENSIONS;*e;e++)
189 while (*e && *e != ' ')
191 if (e - start == len)
192 if (!strncasecmp(start, name, len))
202 returns true if the extension is supported by the server
204 checkextension(extensionname)
207 void PF_checkextension (void)
209 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
216 This is a TERMINAL error, which will kill off the entire server.
225 char string[STRINGTEMP_LENGTH];
227 PF_VarString(0, string, sizeof(string));
228 Con_Printf("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
229 ed = PROG_TO_EDICT(pr_global_struct->self);
232 PF_ERROR("Program error");
239 Dumps out self, then an error message. The program is aborted and self is
240 removed, but the level can continue.
245 void PF_objerror (void)
248 char string[STRINGTEMP_LENGTH];
250 PF_VarString(0, string, sizeof(string));
251 Con_Printf("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
252 ed = PROG_TO_EDICT(pr_global_struct->self);
262 Writes new values for v_forward, v_up, and v_right based on angles
266 void PF_makevectors (void)
268 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
275 Writes new values for v_forward, v_up, and v_right based on the given forward vector
276 vectorvectors(vector, vector)
279 void PF_vectorvectors (void)
281 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
282 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
289 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.
291 setorigin (entity, origin)
294 void PF_setorigin (void)
299 e = G_EDICT(OFS_PARM0);
301 PF_WARNING("setorigin: can not modify world entity\n");
303 PF_WARNING("setorigin: can not modify free entity\n");
304 org = G_VECTOR(OFS_PARM1);
305 VectorCopy (org, e->v->origin);
306 SV_LinkEdict (e, false);
310 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
314 for (i=0 ; i<3 ; i++)
316 PF_ERROR("SetMinMaxSize: backwards mins/maxs\n");
318 // set derived values
319 VectorCopy (min, e->v->mins);
320 VectorCopy (max, e->v->maxs);
321 VectorSubtract (max, min, e->v->size);
323 SV_LinkEdict (e, false);
330 the size box is rotated by the current angle
331 LordHavoc: no it isn't...
333 setsize (entity, minvector, maxvector)
336 void PF_setsize (void)
341 e = G_EDICT(OFS_PARM0);
343 PF_WARNING("setsize: can not modify world entity\n");
345 PF_WARNING("setsize: can not modify free entity\n");
346 min = G_VECTOR(OFS_PARM1);
347 max = G_VECTOR(OFS_PARM2);
348 SetMinMaxSize (e, min, max, false);
356 setmodel(entity, model)
359 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
360 void PF_setmodel (void)
366 e = G_EDICT(OFS_PARM0);
368 PF_WARNING("setmodel: can not modify world entity\n");
370 PF_WARNING("setmodel: can not modify free entity\n");
371 i = SV_ModelIndex(G_STRING(OFS_PARM1), 1);
372 e->v->model = PR_SetString(sv.model_precache[i]);
373 e->v->modelindex = i;
379 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
380 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
382 SetMinMaxSize (e, quakemins, quakemaxs, true);
385 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
392 broadcast print to everyone on server
397 void PF_bprint (void)
399 char string[STRINGTEMP_LENGTH];
400 PF_VarString(0, string, sizeof(string));
401 SV_BroadcastPrint(string);
408 single print to a specific client
410 sprint(clientent, value)
413 void PF_sprint (void)
417 char string[STRINGTEMP_LENGTH];
419 entnum = G_EDICTNUM(OFS_PARM0);
421 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
423 Con_Print("tried to sprint to a non-client\n");
427 client = svs.clients + entnum-1;
428 PF_VarString(1, string, sizeof(string));
429 MSG_WriteChar(&client->message,svc_print);
430 MSG_WriteString(&client->message, string);
438 single print to a specific client
440 centerprint(clientent, value)
443 void PF_centerprint (void)
447 char string[STRINGTEMP_LENGTH];
449 entnum = G_EDICTNUM(OFS_PARM0);
451 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
453 Con_Print("tried to sprint to a non-client\n");
457 client = svs.clients + entnum-1;
458 PF_VarString(1, string, sizeof(string));
459 MSG_WriteChar(&client->message,svc_centerprint);
460 MSG_WriteString(&client->message, string);
468 vector normalize(vector)
471 void PF_normalize (void)
477 value1 = G_VECTOR(OFS_PARM0);
479 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
483 newvalue[0] = newvalue[1] = newvalue[2] = 0;
487 newvalue[0] = value1[0] * new;
488 newvalue[1] = value1[1] * new;
489 newvalue[2] = value1[2] * new;
492 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
507 value1 = G_VECTOR(OFS_PARM0);
509 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
512 G_FLOAT(OFS_RETURN) = new;
519 float vectoyaw(vector)
522 void PF_vectoyaw (void)
527 value1 = G_VECTOR(OFS_PARM0);
529 if (value1[1] == 0 && value1[0] == 0)
533 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
538 G_FLOAT(OFS_RETURN) = yaw;
546 vector vectoangles(vector)
549 void PF_vectoangles (void)
551 double value1[3], forward, yaw, pitch;
553 VectorCopy(G_VECTOR(OFS_PARM0), value1);
555 if (value1[1] == 0 && value1[0] == 0)
565 // LordHavoc: optimized a bit
568 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
572 else if (value1[1] > 0)
577 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
578 pitch = (atan2(value1[2], forward) * 180 / M_PI);
583 VectorSet(G_VECTOR(OFS_RETURN), pitch, yaw, 0);
590 Returns a number from 0<= num < 1
595 void PF_random (void)
597 G_FLOAT(OFS_RETURN) = lhrandom(0, 1);
604 particle(origin, color, count)
607 void PF_particle (void)
613 org = G_VECTOR(OFS_PARM0);
614 dir = G_VECTOR(OFS_PARM1);
615 color = G_FLOAT(OFS_PARM2);
616 count = G_FLOAT(OFS_PARM3);
617 SV_StartParticle (org, dir, color, count);
627 void PF_ambientsound (void)
631 float vol, attenuation;
634 pos = G_VECTOR (OFS_PARM0);
635 samp = G_STRING(OFS_PARM1);
636 vol = G_FLOAT(OFS_PARM2);
637 attenuation = G_FLOAT(OFS_PARM3);
639 // check to see if samp was properly precached
640 soundnum = SV_SoundIndex(samp, 1);
648 // add an svc_spawnambient command to the level signon packet
651 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
653 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
655 MSG_WriteVector(&sv.signon, pos, sv.protocol);
658 MSG_WriteShort (&sv.signon, soundnum);
660 MSG_WriteByte (&sv.signon, soundnum);
662 MSG_WriteByte (&sv.signon, vol*255);
663 MSG_WriteByte (&sv.signon, attenuation*64);
671 Each entity can have eight independant sound sources, like voice,
674 Channel 0 is an auto-allocate channel, the others override anything
675 already running on that entity/channel pair.
677 An attenuation of 0 will play full volume everywhere in the level.
678 Larger attenuations will drop off.
690 entity = G_EDICT(OFS_PARM0);
691 channel = G_FLOAT(OFS_PARM1);
692 sample = G_STRING(OFS_PARM2);
693 volume = G_FLOAT(OFS_PARM3) * 255;
694 attenuation = G_FLOAT(OFS_PARM4);
696 if (volume < 0 || volume > 255)
697 PF_WARNING("SV_StartSound: volume must be in range 0-1\n");
699 if (attenuation < 0 || attenuation > 4)
700 PF_WARNING("SV_StartSound: attenuation must be in range 0-4\n");
702 if (channel < 0 || channel > 7)
703 PF_WARNING("SV_StartSound: channel must be in range 0-7\n");
705 SV_StartSound (entity, channel, sample, volume, attenuation);
717 PF_ERROR("break: break statement\n");
724 Used for use tracing and shot targeting
725 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
726 if the tryents flag is set.
728 traceline (vector1, vector2, tryents)
731 void PF_traceline (void)
738 pr_xfunction->builtinsprofile += 30;
740 v1 = G_VECTOR(OFS_PARM0);
741 v2 = G_VECTOR(OFS_PARM1);
742 move = G_FLOAT(OFS_PARM2);
743 ent = G_EDICT(OFS_PARM3);
745 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, move, ent);
747 pr_global_struct->trace_allsolid = trace.allsolid;
748 pr_global_struct->trace_startsolid = trace.startsolid;
749 pr_global_struct->trace_fraction = trace.fraction;
750 pr_global_struct->trace_inwater = trace.inwater;
751 pr_global_struct->trace_inopen = trace.inopen;
752 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
753 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
754 pr_global_struct->trace_plane_dist = trace.plane.dist;
756 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
758 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
759 // FIXME: add trace_endcontents
767 Used for use tracing and shot targeting
768 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
769 if the tryents flag is set.
771 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
774 // LordHavoc: added this for my own use, VERY useful, similar to traceline
775 void PF_tracebox (void)
777 float *v1, *v2, *m1, *m2;
782 pr_xfunction->builtinsprofile += 30;
784 v1 = G_VECTOR(OFS_PARM0);
785 m1 = G_VECTOR(OFS_PARM1);
786 m2 = G_VECTOR(OFS_PARM2);
787 v2 = G_VECTOR(OFS_PARM3);
788 move = G_FLOAT(OFS_PARM4);
789 ent = G_EDICT(OFS_PARM5);
791 trace = SV_Move (v1, m1, m2, v2, move, ent);
793 pr_global_struct->trace_allsolid = trace.allsolid;
794 pr_global_struct->trace_startsolid = trace.startsolid;
795 pr_global_struct->trace_fraction = trace.fraction;
796 pr_global_struct->trace_inwater = trace.inwater;
797 pr_global_struct->trace_inopen = trace.inopen;
798 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
799 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
800 pr_global_struct->trace_plane_dist = trace.plane.dist;
802 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
804 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
807 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
808 void PF_TraceToss (void)
814 pr_xfunction->builtinsprofile += 600;
816 ent = G_EDICT(OFS_PARM0);
817 if (ent == sv.edicts)
818 PF_WARNING("tracetoss: can not use world entity\n");
819 ignore = G_EDICT(OFS_PARM1);
821 trace = SV_Trace_Toss (ent, ignore);
823 pr_global_struct->trace_allsolid = trace.allsolid;
824 pr_global_struct->trace_startsolid = trace.startsolid;
825 pr_global_struct->trace_fraction = trace.fraction;
826 pr_global_struct->trace_inwater = trace.inwater;
827 pr_global_struct->trace_inopen = trace.inopen;
828 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
829 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
830 pr_global_struct->trace_plane_dist = trace.plane.dist;
832 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
834 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
842 Returns true if the given entity can move to the given position from it's
843 current position by walking or rolling.
845 scalar checkpos (entity, vector)
848 void PF_checkpos (void)
852 //============================================================================
855 qbyte checkpvs[MAX_MAP_LEAFS/8];
857 int PF_newcheckclient (int check)
863 // cycle to the next one
865 check = bound(1, check, svs.maxclients);
866 if (check == svs.maxclients)
874 pr_xfunction->builtinsprofile++;
876 if (i == svs.maxclients+1)
878 // look up the client's edict
880 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
881 if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET)))
883 // found a valid client (possibly the same one again)
887 // get the PVS for the entity
888 VectorAdd(ent->v->origin, ent->v->view_ofs, org);
890 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
891 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
900 Returns a client (or object that has a client enemy) that would be a
903 If there is more than one valid option, they are cycled each frame
905 If (self.origin + self.viewofs) is not in the PVS of the current target,
906 it is not returned at all.
911 int c_invis, c_notvis;
912 void PF_checkclient (void)
917 // find a new check if on a new frame
918 if (sv.time - sv.lastchecktime >= 0.1)
920 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
921 sv.lastchecktime = sv.time;
924 // return check if it might be visible
925 ent = EDICT_NUM(sv.lastcheck);
926 if (ent->e->free || ent->v->health <= 0)
928 RETURN_EDICT(sv.edicts);
932 // if current entity can't possibly see the check entity, return 0
933 self = PROG_TO_EDICT(pr_global_struct->self);
934 VectorAdd(self->v->origin, self->v->view_ofs, view);
935 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
938 RETURN_EDICT(sv.edicts);
942 // might be able to see it
947 //============================================================================
954 Sends text over to the client's execution buffer
956 stuffcmd (clientent, value)
959 void PF_stuffcmd (void)
965 entnum = G_EDICTNUM(OFS_PARM0);
966 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
968 Con_Print("Can't stuffcmd to a non-client\n");
971 str = G_STRING(OFS_PARM1);
974 host_client = svs.clients + entnum-1;
975 Host_ClientCommands ("%s", str);
983 Sends text to server console
988 void PF_localcmd (void)
990 Cbuf_AddText(G_STRING(OFS_PARM0));
1002 G_FLOAT(OFS_RETURN) = Cvar_VariableValue(G_STRING(OFS_PARM0));
1012 void PF_cvar_set (void)
1014 Cvar_Set(G_STRING(OFS_PARM0), G_STRING(OFS_PARM1));
1021 Returns a chain of entities that have origins within a spherical area
1023 findradius (origin, radius)
1026 void PF_findradius (void)
1028 edict_t *ent, *chain;
1029 vec_t radius, radius2;
1030 vec3_t org, eorg, mins, maxs;
1033 edict_t *touchedicts[MAX_EDICTS];
1035 chain = (edict_t *)sv.edicts;
1037 VectorCopy(G_VECTOR(OFS_PARM0), org);
1038 radius = G_FLOAT(OFS_PARM1);
1039 radius2 = radius * radius;
1041 mins[0] = org[0] - radius;
1042 mins[1] = org[1] - radius;
1043 mins[2] = org[2] - radius;
1044 maxs[0] = org[0] + radius;
1045 maxs[1] = org[1] + radius;
1046 maxs[2] = org[2] + radius;
1047 numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
1048 if (numtouchedicts > MAX_EDICTS)
1050 // this never happens
1051 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
1052 numtouchedicts = MAX_EDICTS;
1054 for (i = 0;i < numtouchedicts;i++)
1056 ent = touchedicts[i];
1057 pr_xfunction->builtinsprofile++;
1058 // LordHavoc: compare against bounding box rather than center so it
1059 // doesn't miss large objects, and use DotProduct instead of Length
1060 // for a major speedup
1061 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1062 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1063 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1064 if (DotProduct(eorg, eorg) < radius2)
1066 ent->v->chain = EDICT_TO_PROG(chain);
1071 RETURN_EDICT(chain);
1080 void PF_dprint (void)
1082 char string[STRINGTEMP_LENGTH];
1083 if (developer.integer)
1085 PF_VarString(0, string, sizeof(string));
1094 v = G_FLOAT(OFS_PARM0);
1096 s = PR_GetTempString();
1097 if ((float)((int)v) == v)
1098 sprintf(s, "%i", (int)v);
1100 sprintf(s, "%f", v);
1101 G_INT(OFS_RETURN) = PR_SetString(s);
1107 v = G_FLOAT(OFS_PARM0);
1108 G_FLOAT(OFS_RETURN) = fabs(v);
1114 s = PR_GetTempString();
1115 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1116 G_INT(OFS_RETURN) = PR_SetString(s);
1122 s = PR_GetTempString();
1123 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1124 G_INT(OFS_RETURN) = PR_SetString(s);
1127 void PF_Spawn (void)
1130 pr_xfunction->builtinsprofile += 20;
1135 void PF_Remove (void)
1138 pr_xfunction->builtinsprofile += 20;
1140 ed = G_EDICT(OFS_PARM0);
1141 if (ed == sv.edicts)
1142 PF_WARNING("remove: tried to remove world\n");
1143 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1144 PF_WARNING("remove: tried to remove a client\n");
1145 // LordHavoc: not an error because id1 progs did this in some cases (killtarget removes entities, even if they are already removed in some cases...)
1146 if (ed->e->free && developer.integer)
1147 PF_WARNING("remove: tried to remove an entity that was already removed\n");
1152 // entity (entity start, .string field, string match) find = #5;
1160 e = G_EDICTNUM(OFS_PARM0);
1161 f = G_INT(OFS_PARM1);
1162 s = G_STRING(OFS_PARM2);
1165 RETURN_EDICT(sv.edicts);
1169 for (e++ ; e < sv.num_edicts ; e++)
1171 pr_xfunction->builtinsprofile++;
1185 RETURN_EDICT(sv.edicts);
1188 // LordHavoc: added this for searching float, int, and entity reference fields
1189 void PF_FindFloat (void)
1196 e = G_EDICTNUM(OFS_PARM0);
1197 f = G_INT(OFS_PARM1);
1198 s = G_FLOAT(OFS_PARM2);
1200 for (e++ ; e < sv.num_edicts ; e++)
1202 pr_xfunction->builtinsprofile++;
1206 if (E_FLOAT(ed,f) == s)
1213 RETURN_EDICT(sv.edicts);
1216 // chained search for strings in entity fields
1217 // entity(.string field, string match) findchain = #402;
1218 void PF_findchain (void)
1223 edict_t *ent, *chain;
1225 chain = (edict_t *)sv.edicts;
1227 f = G_INT(OFS_PARM0);
1228 s = G_STRING(OFS_PARM1);
1231 RETURN_EDICT(sv.edicts);
1235 ent = NEXT_EDICT(sv.edicts);
1236 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1238 pr_xfunction->builtinsprofile++;
1241 t = E_STRING(ent,f);
1247 ent->v->chain = EDICT_TO_PROG(chain);
1251 RETURN_EDICT(chain);
1254 // LordHavoc: chained search for float, int, and entity reference fields
1255 // entity(.string field, float match) findchainfloat = #403;
1256 void PF_findchainfloat (void)
1261 edict_t *ent, *chain;
1263 chain = (edict_t *)sv.edicts;
1265 f = G_INT(OFS_PARM0);
1266 s = G_FLOAT(OFS_PARM1);
1268 ent = NEXT_EDICT(sv.edicts);
1269 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1271 pr_xfunction->builtinsprofile++;
1274 if (E_FLOAT(ent,f) != s)
1277 ent->v->chain = EDICT_TO_PROG(chain);
1281 RETURN_EDICT(chain);
1284 // LordHavoc: search for flags in float fields
1285 void PF_findflags (void)
1292 e = G_EDICTNUM(OFS_PARM0);
1293 f = G_INT(OFS_PARM1);
1294 s = (int)G_FLOAT(OFS_PARM2);
1296 for (e++ ; e < sv.num_edicts ; e++)
1298 pr_xfunction->builtinsprofile++;
1302 if ((int)E_FLOAT(ed,f) & s)
1309 RETURN_EDICT(sv.edicts);
1312 // LordHavoc: chained search for flags in float fields
1313 void PF_findchainflags (void)
1318 edict_t *ent, *chain;
1320 chain = (edict_t *)sv.edicts;
1322 f = G_INT(OFS_PARM0);
1323 s = (int)G_FLOAT(OFS_PARM1);
1325 ent = NEXT_EDICT(sv.edicts);
1326 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1328 pr_xfunction->builtinsprofile++;
1331 if (!((int)E_FLOAT(ent,f) & s))
1334 ent->v->chain = EDICT_TO_PROG(chain);
1338 RETURN_EDICT(chain);
1341 void PR_CheckEmptyString (char *s)
1344 PF_ERROR("Bad string");
1347 void PF_precache_file (void)
1348 { // precache_file is only used to copy files with qcc, it does nothing
1349 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1353 void PF_precache_sound (void)
1355 SV_SoundIndex(G_STRING(OFS_PARM0), 2);
1356 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1359 void PF_precache_model (void)
1361 SV_ModelIndex(G_STRING(OFS_PARM0), 2);
1362 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1366 void PF_coredump (void)
1371 void PF_traceon (void)
1376 void PF_traceoff (void)
1381 void PF_eprint (void)
1383 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1390 float(float yaw, float dist) walkmove
1393 void PF_walkmove (void)
1401 // assume failure if it returns early
1402 G_FLOAT(OFS_RETURN) = 0;
1404 ent = PROG_TO_EDICT(pr_global_struct->self);
1405 if (ent == sv.edicts)
1406 PF_WARNING("walkmove: can not modify world entity\n");
1408 PF_WARNING("walkmove: can not modify free entity\n");
1409 yaw = G_FLOAT(OFS_PARM0);
1410 dist = G_FLOAT(OFS_PARM1);
1412 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1415 yaw = yaw*M_PI*2 / 360;
1417 move[0] = cos(yaw)*dist;
1418 move[1] = sin(yaw)*dist;
1421 // save program state, because SV_movestep may call other progs
1422 oldf = pr_xfunction;
1423 oldself = pr_global_struct->self;
1425 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1428 // restore program state
1429 pr_xfunction = oldf;
1430 pr_global_struct->self = oldself;
1440 void PF_droptofloor (void)
1446 // assume failure if it returns early
1447 G_FLOAT(OFS_RETURN) = 0;
1449 ent = PROG_TO_EDICT(pr_global_struct->self);
1450 if (ent == sv.edicts)
1451 PF_WARNING("droptofloor: can not modify world entity\n");
1453 PF_WARNING("droptofloor: can not modify free entity\n");
1455 VectorCopy (ent->v->origin, end);
1458 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1460 if (trace.fraction != 1)
1462 VectorCopy (trace.endpos, ent->v->origin);
1463 SV_LinkEdict (ent, false);
1464 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1465 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1466 G_FLOAT(OFS_RETURN) = 1;
1467 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1468 ent->e->suspendedinairflag = true;
1476 void(float style, string value) lightstyle
1479 void PF_lightstyle (void)
1486 style = G_FLOAT(OFS_PARM0);
1487 val = G_STRING(OFS_PARM1);
1489 // change the string in sv
1490 sv.lightstyles[style] = val;
1492 // send message to all clients on this server
1493 if (sv.state != ss_active)
1496 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1500 MSG_WriteChar (&client->message, svc_lightstyle);
1501 MSG_WriteChar (&client->message,style);
1502 MSG_WriteString (&client->message, val);
1510 f = G_FLOAT(OFS_PARM0);
1512 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1514 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1516 void PF_floor (void)
1518 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1522 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1531 void PF_checkbottom (void)
1533 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1541 void PF_pointcontents (void)
1543 G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1550 entity nextent(entity)
1553 void PF_nextent (void)
1558 i = G_EDICTNUM(OFS_PARM0);
1561 pr_xfunction->builtinsprofile++;
1563 if (i == sv.num_edicts)
1565 RETURN_EDICT(sv.edicts);
1581 Pick a vector for the player to shoot along
1582 vector aim(entity, missilespeed)
1587 edict_t *ent, *check, *bestent;
1588 vec3_t start, dir, end, bestdir;
1591 float dist, bestdist;
1594 // assume failure if it returns early
1595 VectorCopy(pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1596 // if sv_aim is so high it can't possibly accept anything, skip out early
1597 if (sv_aim.value >= 1)
1600 ent = G_EDICT(OFS_PARM0);
1601 if (ent == sv.edicts)
1602 PF_WARNING("aim: can not use world entity\n");
1604 PF_WARNING("aim: can not use free entity\n");
1605 speed = G_FLOAT(OFS_PARM1);
1607 VectorCopy (ent->v->origin, start);
1610 // try sending a trace straight
1611 VectorCopy (pr_global_struct->v_forward, dir);
1612 VectorMA (start, 2048, dir, end);
1613 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1614 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1615 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1617 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1622 // try all possible entities
1623 VectorCopy (dir, bestdir);
1624 bestdist = sv_aim.value;
1627 check = NEXT_EDICT(sv.edicts);
1628 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1630 pr_xfunction->builtinsprofile++;
1631 if (check->v->takedamage != DAMAGE_AIM)
1635 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1636 continue; // don't aim at teammate
1637 for (j=0 ; j<3 ; j++)
1638 end[j] = check->v->origin[j]
1639 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1640 VectorSubtract (end, start, dir);
1641 VectorNormalize (dir);
1642 dist = DotProduct (dir, pr_global_struct->v_forward);
1643 if (dist < bestdist)
1644 continue; // to far to turn
1645 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1646 if (tr.ent == check)
1647 { // can shoot at this one
1655 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1656 dist = DotProduct (dir, pr_global_struct->v_forward);
1657 VectorScale (pr_global_struct->v_forward, dist, end);
1659 VectorNormalize (end);
1660 VectorCopy (end, G_VECTOR(OFS_RETURN));
1664 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1672 This was a major timewaster in progs, so it was converted to C
1675 void PF_changeyaw (void)
1678 float ideal, current, move, speed;
1680 ent = PROG_TO_EDICT(pr_global_struct->self);
1681 if (ent == sv.edicts)
1682 PF_WARNING("changeyaw: can not modify world entity\n");
1684 PF_WARNING("changeyaw: can not modify free entity\n");
1685 current = ANGLEMOD(ent->v->angles[1]);
1686 ideal = ent->v->ideal_yaw;
1687 speed = ent->v->yaw_speed;
1689 if (current == ideal)
1691 move = ideal - current;
1692 if (ideal > current)
1713 ent->v->angles[1] = ANGLEMOD (current + move);
1721 void PF_changepitch (void)
1724 float ideal, current, move, speed;
1727 ent = G_EDICT(OFS_PARM0);
1728 if (ent == sv.edicts)
1729 PF_WARNING("changepitch: can not modify world entity\n");
1731 PF_WARNING("changepitch: can not modify free entity\n");
1732 current = ANGLEMOD( ent->v->angles[0] );
1733 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1734 ideal = val->_float;
1737 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1740 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1741 speed = val->_float;
1744 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1748 if (current == ideal)
1750 move = ideal - current;
1751 if (ideal > current)
1772 ent->v->angles[0] = ANGLEMOD (current + move);
1776 ===============================================================================
1780 ===============================================================================
1783 #define MSG_BROADCAST 0 // unreliable to all
1784 #define MSG_ONE 1 // reliable to one (msg_entity)
1785 #define MSG_ALL 2 // reliable to all
1786 #define MSG_INIT 3 // write to the init string
1788 sizebuf_t *WriteDest (void)
1794 dest = G_FLOAT(OFS_PARM0);
1798 return &sv.datagram;
1801 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1802 entnum = NUM_FOR_EDICT(ent);
1803 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1804 Host_Error("WriteDest: tried to write to non-client\n");
1805 return &svs.clients[entnum-1].message;
1808 return &sv.reliable_datagram;
1814 Host_Error("WriteDest: bad destination");
1821 void PF_WriteByte (void)
1823 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1826 void PF_WriteChar (void)
1828 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1831 void PF_WriteShort (void)
1833 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1836 void PF_WriteLong (void)
1838 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1841 void PF_WriteAngle (void)
1843 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1846 void PF_WriteCoord (void)
1848 MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1851 void PF_WriteString (void)
1853 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1857 void PF_WriteEntity (void)
1859 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1862 //=============================================================================
1864 void PF_makestatic (void)
1869 ent = G_EDICT(OFS_PARM0);
1870 if (ent == sv.edicts)
1871 PF_WARNING("makestatic: can not modify world entity\n");
1873 PF_WARNING("makestatic: can not modify free entity\n");
1876 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1881 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1882 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1883 MSG_WriteShort (&sv.signon, ent->v->frame);
1887 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1888 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1889 MSG_WriteByte (&sv.signon, ent->v->frame);
1892 MSG_WriteByte (&sv.signon, ent->v->colormap);
1893 MSG_WriteByte (&sv.signon, ent->v->skin);
1894 for (i=0 ; i<3 ; i++)
1896 MSG_WriteCoord(&sv.signon, ent->v->origin[i], sv.protocol);
1897 MSG_WriteAngle(&sv.signon, ent->v->angles[i], sv.protocol);
1900 // throw the entity away now
1904 //=============================================================================
1911 void PF_setspawnparms (void)
1917 ent = G_EDICT(OFS_PARM0);
1918 i = NUM_FOR_EDICT(ent);
1919 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1921 Con_Print("tried to setspawnparms on a non-client\n");
1925 // copy spawn parms out of the client_t
1926 client = svs.clients + i-1;
1927 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1928 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1936 void PF_changelevel (void)
1940 // make sure we don't issue two changelevels
1941 if (svs.changelevel_issued)
1943 svs.changelevel_issued = true;
1945 s = G_STRING(OFS_PARM0);
1946 Cbuf_AddText (va("changelevel %s\n",s));
1951 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1956 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1961 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1968 Returns a vector of length < 1
1973 void PF_randomvec (void)
1978 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1979 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1980 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1982 while (DotProduct(temp, temp) >= 1);
1983 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1990 Returns a color vector indicating the lighting at the requested point.
1992 (Internal Operation note: actually measures the light beneath the point, just like
1993 the model lighting on the client)
1998 void PF_GetLight (void)
2000 vec3_t ambientcolor, diffusecolor, diffusenormal;
2002 p = G_VECTOR(OFS_PARM0);
2003 VectorClear(ambientcolor);
2004 VectorClear(diffusecolor);
2005 VectorClear(diffusenormal);
2006 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
2007 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
2008 VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
2011 void PF_registercvar (void)
2014 name = G_STRING(OFS_PARM0);
2015 value = G_STRING(OFS_PARM1);
2016 G_FLOAT(OFS_RETURN) = 0;
2018 // first check to see if it has already been defined
2019 if (Cvar_FindVar (name))
2022 // check for overlap with a command
2023 if (Cmd_Exists (name))
2025 Con_Printf("PF_registercvar: %s is a command\n", name);
2029 Cvar_Get(name, value, 0);
2031 G_FLOAT(OFS_RETURN) = 1; // success
2038 returns the minimum of two supplied floats
2045 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2047 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2048 else if (pr_argc >= 3)
2051 float f = G_FLOAT(OFS_PARM0);
2052 for (i = 1;i < pr_argc;i++)
2053 if (G_FLOAT((OFS_PARM0+i*3)) < f)
2054 f = G_FLOAT((OFS_PARM0+i*3));
2055 G_FLOAT(OFS_RETURN) = f;
2059 G_FLOAT(OFS_RETURN) = 0;
2060 PF_WARNING("min: must supply at least 2 floats\n");
2068 returns the maximum of two supplied floats
2075 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2077 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2078 else if (pr_argc >= 3)
2081 float f = G_FLOAT(OFS_PARM0);
2082 for (i = 1;i < pr_argc;i++)
2083 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2084 f = G_FLOAT((OFS_PARM0+i*3));
2085 G_FLOAT(OFS_RETURN) = f;
2089 G_FLOAT(OFS_RETURN) = 0;
2090 PF_WARNING("max: must supply at least 2 floats\n");
2098 returns number bounded by supplied range
2100 min(min, value, max)
2103 void PF_bound (void)
2105 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2112 returns a raised to power b
2119 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2126 copies data from one entity to another
2128 copyentity(src, dst)
2131 void PF_copyentity (void)
2134 in = G_EDICT(OFS_PARM0);
2135 if (in == sv.edicts)
2136 PF_WARNING("copyentity: can not read world entity\n");
2138 PF_WARNING("copyentity: can not read free entity\n");
2139 out = G_EDICT(OFS_PARM1);
2140 if (out == sv.edicts)
2141 PF_WARNING("copyentity: can not modify world entity\n");
2143 PF_WARNING("copyentity: can not modify free entity\n");
2144 memcpy(out->v, in->v, progs->entityfields * 4);
2151 sets the color of a client and broadcasts the update to all connected clients
2153 setcolor(clientent, value)
2156 void PF_setcolor (void)
2162 entnum = G_EDICTNUM(OFS_PARM0);
2163 i = G_FLOAT(OFS_PARM1);
2165 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2167 Con_Print("tried to setcolor a non-client\n");
2171 client = svs.clients + entnum-1;
2174 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2176 client->edict->v->team = (i & 15) + 1;
2179 if (client->old_colors != client->colors)
2181 client->old_colors = client->colors;
2182 // send notification to all clients
2183 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2184 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
2185 MSG_WriteByte (&sv.reliable_datagram, client->colors);
2193 effect(origin, modelname, startframe, framecount, framerate)
2196 void PF_effect (void)
2200 s = G_STRING(OFS_PARM1);
2202 PF_WARNING("effect: no model specified\n");
2204 i = SV_ModelIndex(s, 1);
2206 PF_WARNING("effect: model not precached\n");
2207 SV_StartEffect(G_VECTOR(OFS_PARM0), i, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2210 void PF_te_blood (void)
2212 if (G_FLOAT(OFS_PARM2) < 1)
2214 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2215 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2217 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2218 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2219 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2221 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2222 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2223 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2225 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2228 void PF_te_bloodshower (void)
2230 if (G_FLOAT(OFS_PARM3) < 1)
2232 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2233 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2235 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2236 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2237 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2239 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2240 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2241 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2243 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM2), sv.protocol);
2245 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2248 void PF_te_explosionrgb (void)
2250 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2251 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2253 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2254 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2255 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2257 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2258 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2259 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2262 void PF_te_particlecube (void)
2264 if (G_FLOAT(OFS_PARM3) < 1)
2266 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2267 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2269 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2270 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2271 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2273 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2274 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2275 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2277 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2278 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2279 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2281 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2283 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2284 // gravity true/false
2285 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2287 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM6), sv.protocol);
2290 void PF_te_particlerain (void)
2292 if (G_FLOAT(OFS_PARM3) < 1)
2294 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2295 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2297 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2298 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2299 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2301 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2302 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2303 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2305 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2306 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2307 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2309 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2311 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2314 void PF_te_particlesnow (void)
2316 if (G_FLOAT(OFS_PARM3) < 1)
2318 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2319 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2321 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2322 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2323 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2325 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2326 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2327 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2329 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2330 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2331 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2333 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2335 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2338 void PF_te_spark (void)
2340 if (G_FLOAT(OFS_PARM2) < 1)
2342 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2343 MSG_WriteByte(&sv.datagram, TE_SPARK);
2345 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2346 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2347 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2349 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2350 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2351 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2353 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2356 void PF_te_gunshotquad (void)
2358 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2359 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2361 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2362 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2363 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2366 void PF_te_spikequad (void)
2368 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2369 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2371 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2372 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2373 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2376 void PF_te_superspikequad (void)
2378 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2379 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2381 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2382 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2383 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2386 void PF_te_explosionquad (void)
2388 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2389 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2391 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2392 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2393 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2396 void PF_te_smallflash (void)
2398 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2399 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2401 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2402 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2403 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2406 void PF_te_customflash (void)
2408 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2410 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2411 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2413 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2414 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2415 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2417 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2419 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2421 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2422 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2423 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2426 void PF_te_gunshot (void)
2428 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2429 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2431 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2432 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2433 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2436 void PF_te_spike (void)
2438 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2439 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2441 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2442 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2443 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2446 void PF_te_superspike (void)
2448 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2449 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2451 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2452 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2453 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2456 void PF_te_explosion (void)
2458 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2459 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2461 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2462 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2463 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2466 void PF_te_tarexplosion (void)
2468 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2469 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2471 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2472 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2473 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2476 void PF_te_wizspike (void)
2478 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2479 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2481 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2482 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2483 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2486 void PF_te_knightspike (void)
2488 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2489 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2491 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2492 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2493 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2496 void PF_te_lavasplash (void)
2498 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2499 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2501 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2502 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2503 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2506 void PF_te_teleport (void)
2508 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2509 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2511 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2512 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2513 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2516 void PF_te_explosion2 (void)
2518 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2519 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2521 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2522 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2523 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2525 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2526 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM2));
2529 void PF_te_lightning1 (void)
2531 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2532 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2534 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2536 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2537 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2538 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2540 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2541 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2542 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2545 void PF_te_lightning2 (void)
2547 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2548 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2550 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2552 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2553 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2554 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2556 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2557 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2558 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2561 void PF_te_lightning3 (void)
2563 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2564 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2566 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2568 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2569 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2570 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2572 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2573 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2574 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2577 void PF_te_beam (void)
2579 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2580 MSG_WriteByte(&sv.datagram, TE_BEAM);
2582 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2584 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2585 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2586 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2588 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2589 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2590 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2593 void PF_te_plasmaburn (void)
2595 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2596 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2597 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2598 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2599 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2602 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2605 vec3_t v1, clipplanenormal, normal;
2606 vec_t clipplanedist, clipdist;
2608 if (surf->flags & SURF_PLANEBACK)
2609 VectorNegate(surf->plane->normal, normal);
2611 VectorCopy(surf->plane->normal, normal);
2612 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2614 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2615 VectorNormalizeFast(v1);
2616 CrossProduct(v1, normal, clipplanenormal);
2617 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2618 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2621 clipdist = -clipdist;
2622 VectorMA(out, clipdist, clipplanenormal, out);
2627 static msurface_t *getsurface(edict_t *ed, int surfnum)
2631 if (!ed || ed->e->free)
2633 modelindex = ed->v->modelindex;
2634 if (modelindex < 1 || modelindex >= MAX_MODELS)
2636 model = sv.models[modelindex];
2637 if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2639 return model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2643 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2644 void PF_getsurfacenumpoints(void)
2647 // return 0 if no such surface
2648 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2650 G_FLOAT(OFS_RETURN) = 0;
2654 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2656 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2657 void PF_getsurfacepoint(void)
2662 VectorClear(G_VECTOR(OFS_RETURN));
2663 ed = G_EDICT(OFS_PARM0);
2664 if (!ed || ed->e->free)
2666 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2668 pointnum = G_FLOAT(OFS_PARM2);
2669 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2671 // FIXME: implement rotation/scaling
2672 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2674 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2675 void PF_getsurfacenormal(void)
2678 VectorClear(G_VECTOR(OFS_RETURN));
2679 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2681 // FIXME: implement rotation/scaling
2682 if (surf->flags & SURF_PLANEBACK)
2683 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2685 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2687 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2688 void PF_getsurfacetexture(void)
2691 G_INT(OFS_RETURN) = 0;
2692 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2694 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2696 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2697 void PF_getsurfacenearpoint(void)
2699 int surfnum, best, modelindex;
2701 vec_t dist, bestdist;
2706 G_FLOAT(OFS_RETURN) = -1;
2707 ed = G_EDICT(OFS_PARM0);
2708 point = G_VECTOR(OFS_PARM1);
2710 if (!ed || ed->e->free)
2712 modelindex = ed->v->modelindex;
2713 if (modelindex < 1 || modelindex >= MAX_MODELS)
2715 model = sv.models[modelindex];
2716 if (!model->brushq1.numsurfaces)
2719 // FIXME: implement rotation/scaling
2720 VectorSubtract(point, ed->v->origin, p);
2722 bestdist = 1000000000;
2723 for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2725 surf = model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2726 dist = PlaneDiff(p, surf->plane);
2728 if (dist < bestdist)
2730 clippointtosurface(surf, p, clipped);
2731 VectorSubtract(clipped, p, clipped);
2732 dist += DotProduct(clipped, clipped);
2733 if (dist < bestdist)
2740 G_FLOAT(OFS_RETURN) = best;
2742 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2743 void PF_getsurfaceclippedpoint(void)
2748 VectorClear(G_VECTOR(OFS_RETURN));
2749 ed = G_EDICT(OFS_PARM0);
2750 if (!ed || ed->e->free)
2752 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2754 // FIXME: implement rotation/scaling
2755 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2756 clippointtosurface(surf, p, out);
2757 // FIXME: implement rotation/scaling
2758 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2761 #define MAX_PRFILES 256
2763 qfile_t *pr_files[MAX_PRFILES];
2765 void PR_Files_Init(void)
2767 memset(pr_files, 0, sizeof(pr_files));
2770 void PR_Files_CloseAll(void)
2773 for (i = 0;i < MAX_PRFILES;i++)
2776 FS_Close(pr_files[i]);
2781 //float(string s) stof = #81; // get numerical value from a string
2784 char string[STRINGTEMP_LENGTH];
2785 PF_VarString(0, string, sizeof(string));
2786 G_FLOAT(OFS_RETURN) = atof(string);
2789 //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
2792 int filenum, mode, i;
2793 char *modestring, *filename;
2794 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2795 if (pr_files[filenum] == NULL)
2797 if (filenum >= MAX_PRFILES)
2799 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2800 G_FLOAT(OFS_RETURN) = -2;
2803 mode = G_FLOAT(OFS_PARM1);
2806 case 0: // FILE_READ
2809 case 1: // FILE_APPEND
2812 case 2: // FILE_WRITE
2816 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2817 G_FLOAT(OFS_RETURN) = -3;
2820 filename = G_STRING(OFS_PARM0);
2821 // control characters do not cause issues with any platforms I know of, but they are usually annoying to deal with
2822 // ../ is parent directory on many platforms
2823 // // is parent directory on Amiga
2824 // / at the beginning of a path is root on unix, and parent directory on Amiga
2825 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2826 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2827 for (i = 0;filename[i];i++)
2829 if (filename[i] < ' ' || (filename[i] == '/' && filename[i+1] == '/') || (filename[i] == '.' && filename[i+1] == '.') || filename[i] == ':' || filename[i] == '\\' || filename[0] == '/')
2831 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);
2832 G_FLOAT(OFS_RETURN) = -4;
2836 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2838 if (pr_files[filenum] == NULL && modestring == "rb")
2839 pr_files[filenum] = FS_Open(filename, modestring, false);
2841 if (pr_files[filenum] == NULL)
2842 G_FLOAT(OFS_RETURN) = -1;
2844 G_FLOAT(OFS_RETURN) = filenum;
2847 //void(float fhandle) fclose = #111; // closes a file
2848 void PF_fclose(void)
2850 int filenum = G_FLOAT(OFS_PARM0);
2851 if (filenum < 0 || filenum >= MAX_PRFILES)
2853 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2856 if (pr_files[filenum] == NULL)
2858 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2861 FS_Close(pr_files[filenum]);
2862 pr_files[filenum] = NULL;
2865 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2869 static char string[STRINGTEMP_LENGTH];
2870 int filenum = G_FLOAT(OFS_PARM0);
2871 if (filenum < 0 || filenum >= MAX_PRFILES)
2873 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2876 if (pr_files[filenum] == NULL)
2878 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2884 c = FS_Getc(pr_files[filenum]);
2885 if (c == '\r' || c == '\n' || c < 0)
2887 if (end < STRINGTEMP_LENGTH - 1)
2891 // remove \n following \r
2893 c = FS_Getc(pr_files[filenum]);
2894 if (developer.integer)
2895 Con_Printf("fgets: %s\n", string);
2897 G_INT(OFS_RETURN) = PR_SetString(string);
2899 G_INT(OFS_RETURN) = 0;
2902 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2906 char string[STRINGTEMP_LENGTH];
2907 int filenum = G_FLOAT(OFS_PARM0);
2908 if (filenum < 0 || filenum >= MAX_PRFILES)
2910 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2913 if (pr_files[filenum] == NULL)
2915 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2918 PF_VarString(1, string, sizeof(string));
2919 if ((stringlength = strlen(string)))
2920 FS_Write(pr_files[filenum], string, stringlength);
2921 if (developer.integer)
2922 Con_Printf("fputs: %s\n", string);
2925 //float(string s) strlen = #114; // returns how many characters are in a string
2926 void PF_strlen(void)
2929 s = G_STRING(OFS_PARM0);
2931 G_FLOAT(OFS_RETURN) = strlen(s);
2933 G_FLOAT(OFS_RETURN) = 0;
2936 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2937 void PF_strcat(void)
2939 char *s = PR_GetTempString();
2940 PF_VarString(0, s, STRINGTEMP_LENGTH);
2941 G_INT(OFS_RETURN) = PR_SetString(s);
2944 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2945 void PF_substring(void)
2947 int i, start, length;
2948 char *s, *string = PR_GetTempString();
2949 s = G_STRING(OFS_PARM0);
2950 start = G_FLOAT(OFS_PARM1);
2951 length = G_FLOAT(OFS_PARM2);
2954 for (i = 0;i < start && *s;i++, s++);
2955 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2958 G_INT(OFS_RETURN) = PR_SetString(string);
2961 //vector(string s) stov = #117; // returns vector value from a string
2964 char string[STRINGTEMP_LENGTH];
2965 PF_VarString(0, string, sizeof(string));
2966 Math_atov(string, G_VECTOR(OFS_RETURN));
2969 //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)
2970 void PF_strzone(void)
2973 in = G_STRING(OFS_PARM0);
2974 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2976 G_INT(OFS_RETURN) = PR_SetString(out);
2979 //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!!!)
2980 void PF_strunzone(void)
2982 Mem_Free(G_STRING(OFS_PARM0));
2985 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2986 //this function originally written by KrimZon, made shorter by LordHavoc
2987 void PF_clientcommand (void)
2989 client_t *temp_client;
2992 //find client for this entity
2993 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
2994 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2996 Con_Print("PF_clientcommand: entity is not a client\n");
3000 temp_client = host_client;
3001 host_client = svs.clients + i;
3002 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
3003 host_client = temp_client;
3006 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
3007 //this function originally written by KrimZon, made shorter by LordHavoc
3008 //20040203: rewritten by LordHavoc (no longer uses allocations)
3010 char *tokens[256], tokenbuf[4096];
3011 void PF_tokenize (void)
3015 p = G_STRING(OFS_PARM0);
3019 while(COM_ParseToken(&p, false))
3021 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3023 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3025 tokens[num_tokens++] = tokenbuf + pos;
3026 strcpy(tokenbuf + pos, com_token);
3027 pos += strlen(com_token) + 1;
3030 G_FLOAT(OFS_RETURN) = num_tokens;
3033 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3034 //this function originally written by KrimZon, made shorter by LordHavoc
3037 int token_num = G_FLOAT(OFS_PARM0);
3038 if (token_num >= 0 && token_num < num_tokens)
3039 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
3041 G_INT(OFS_RETURN) = PR_SetString("");
3044 //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)
3045 void PF_setattachment (void)
3047 edict_t *e = G_EDICT(OFS_PARM0);
3048 edict_t *tagentity = G_EDICT(OFS_PARM1);
3049 char *tagname = G_STRING(OFS_PARM2);
3055 PF_WARNING("setattachment: can not modify world entity\n");
3057 PF_WARNING("setattachment: can not modify free entity\n");
3059 if (tagentity == NULL)
3060 tagentity = sv.edicts;
3062 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3064 v->edict = EDICT_TO_PROG(tagentity);
3066 v = GETEDICTFIELDVALUE(e, eval_tag_index);
3069 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3071 modelindex = (int)tagentity->v->modelindex;
3072 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3074 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3075 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3076 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3078 // FIXME: use a model function to get tag info (need to handle skeletal)
3079 if (v->_float == 0 && model->alias.aliasnum_tags)
3080 for (i = 0;i < model->alias.aliasnum_tags;i++)
3081 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3084 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);
3087 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));
3091 /////////////////////////////////////////
3092 // DP_MD3_TAGINFO extension coded by VorteX
3094 int SV_GetTagIndex (edict_t *e, char *tagname)
3099 i = e->v->modelindex;
3100 if (i < 1 || i >= MAX_MODELS)
3102 model = sv.models[i];
3105 if (model->data_overridetagnamesforskin && (unsigned int)e->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames)
3107 for (i = 0; i < model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames; i++)
3109 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)e->v->skin].data_overridetagnames[i].name))
3118 for (i = 0;i < model->alias.aliasnum_tags; i++)
3120 if (!(strcmp(tagname, model->alias.aliasdata_tags[i].name)))
3127 return tagindex + 1;
3130 // Warnings/errors code:
3131 // 0 - normal (everything all-right)
3134 // 3 - null or non-precached model
3135 // 4 - no tags with requested index
3136 // 5 - runaway loop at attachment chain
3137 extern cvar_t cl_bob;
3138 extern cvar_t cl_bobcycle;
3139 extern cvar_t cl_bobup;
3140 int SV_GetTagMatrix (matrix4x4_t *out, edict_t *ent, int tagindex)
3143 int modelindex, reqtag, reqframe, attachloop;
3144 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
3148 Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
3150 if (ent == sv.edicts)
3155 modelindex = (int)ent->v->modelindex;
3156 if (modelindex <= 0 || modelindex > MAX_MODELS)
3159 model = sv.models[modelindex];
3160 reqtag = model->alias.aliasnum_tags;
3162 if (tagindex <= 0 || tagindex > reqtag)
3164 if (reqtag && tagindex) // Only appear if model has no tags or not-null tag requested
3169 if (ent->v->frame < 0 || ent->v->frame > model->alias.aliasnum_tagframes)
3170 reqframe = model->numframes - 1; // if model has wrong frame, engine automatically switches to model last frame
3172 reqframe = ent->v->frame;
3174 // get initial tag matrix
3177 reqtag = (tagindex - 1) + ent->v->frame*model->alias.aliasnum_tags;
3178 Matrix4x4_Copy(&tagmatrix, &model->alias.aliasdata_tags[reqtag].matrix);
3181 Matrix4x4_CreateIdentity(&tagmatrix);
3183 if ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict)
3184 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
3188 attachent = EDICT_NUM(val->edict); // to this it entity our entity is attached
3189 val = GETEDICTFIELDVALUE(ent, eval_tag_index);
3190 Matrix4x4_CreateIdentity(&attachmatrix);
3191 if (val->_float >= 1 && attachent->v->modelindex >= 1 && attachent->v->modelindex < MAX_MODELS)
3193 model = sv.models[(int)attachent->v->modelindex];
3194 if (val->_float < model->alias.aliasnum_tags)
3196 // got tagname on parent entity attachment tag via tag_index (and got it's matrix)
3197 model = sv.models[(int)attachent->v->modelindex];
3198 reqtag = (val->_float - 1) + attachent->v->frame*model->alias.aliasnum_tags;
3199 Matrix4x4_Copy(&attachmatrix, &model->alias.aliasdata_tags[reqtag].matrix);
3203 // apply transformation by child entity matrix
3204 val = GETEDICTFIELDVALUE(ent, eval_scale);
3205 if (val->_float == 0)
3207 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);
3208 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3209 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]);
3210 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]);
3211 out->m[2][3] = entitymatrix.m[2][3] + val->_float*(entitymatrix.m[2][0]*tagmatrix.m[0][3] + entitymatrix.m[2][1]*tagmatrix.m[1][3] + entitymatrix.m[2][2]*tagmatrix.m[2][3]);
3212 Matrix4x4_Copy(&tagmatrix, out);
3214 // finally transformate by matrix of tag on parent entity
3215 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
3216 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];
3217 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];
3218 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];
3219 Matrix4x4_Copy(&tagmatrix, out);
3223 if (attachloop > 255) // prevent runaway looping
3226 while ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
3229 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
3230 val = GETEDICTFIELDVALUE(ent, eval_scale);
3231 if (val->_float == 0)
3233 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
3234 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);
3235 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3236 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]);
3237 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]);
3238 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]);
3240 if ((val = GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
3241 {// RENDER_VIEWMODEL magic
3242 Matrix4x4_Copy(&tagmatrix, out);
3243 ent = EDICT_NUM(val->edict);
3245 val = GETEDICTFIELDVALUE(ent, eval_scale);
3246 if (val->_float == 0)
3249 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);
3250 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3251 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]);
3252 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]);
3253 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]);
3256 // Cl_bob, ported from rendering code
3257 if (ent->v->health > 0 && cl_bob.value && cl_bobcycle.value)
3260 // LordHavoc: this code is *weird*, but not replacable (I think it
3261 // should be done in QC on the server, but oh well, quake is quake)
3262 // LordHavoc: figured out bobup: the time at which the sin is at 180
3263 // degrees (which allows lengthening or squishing the peak or valley)
3264 cycle = sv.time/cl_bobcycle.value;
3265 cycle -= (int)cycle;
3266 if (cycle < cl_bobup.value)
3267 cycle = sin(M_PI * cycle / cl_bobup.value);
3269 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
3270 // bob is proportional to velocity in the xy plane
3271 // (don't count Z, or jumping messes it up)
3272 bob = sqrt(ent->v->velocity[0]*ent->v->velocity[0] + ent->v->velocity[1]*ent->v->velocity[1])*cl_bob.value;
3273 bob = bob*0.3 + bob*0.7*cycle;
3274 out->m[2][3] += bound(-7, bob, 4);
3281 //float(entity ent, string tagname) gettagindex;
3283 void PF_gettagindex (void)
3285 edict_t *ent = G_EDICT(OFS_PARM0);
3286 char *tag_name = G_STRING(OFS_PARM1);
3287 int modelindex, tag_index;
3289 if (ent == sv.edicts)
3290 PF_WARNING("gettagindex: can't affect world entity\n");
3292 PF_WARNING("gettagindex: can't affect free entity\n");
3294 modelindex = (int)ent->v->modelindex;
3296 if (modelindex <= 0 || modelindex > MAX_MODELS)
3297 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(ent));
3300 tag_index = SV_GetTagIndex(ent, tag_name);
3302 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", NUM_FOR_EDICT(ent), tag_name);
3304 G_FLOAT(OFS_RETURN) = tag_index;
3307 //vector(entity ent, float tagindex) gettaginfo;
3308 void PF_gettaginfo (void)
3310 edict_t *e = G_EDICT(OFS_PARM0);
3311 int tagindex = (int)G_FLOAT(OFS_PARM1);
3312 matrix4x4_t tag_matrix;
3315 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
3316 Matrix4x4_ToVectors(&tag_matrix, pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up, G_VECTOR(OFS_RETURN));
3321 PF_WARNING("gettagindex: can't affect world entity\n");
3324 PF_WARNING("gettagindex: can't affect free entity\n");
3327 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3330 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", NUM_FOR_EDICT(e), tagindex);
3333 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", NUM_FOR_EDICT(e));
3339 /////////////////////////////////////////
3340 // DP_QC_FS_SEARCH extension
3342 // qc fs search handling
3343 #define MAX_SEARCHES 128
3345 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3347 void PR_Search_Init(void)
3349 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3352 void PR_Search_Reset(void)
3355 // reset the fssearch list
3356 for(i = 0; i < MAX_SEARCHES; i++)
3357 if(pr_fssearchlist[i])
3358 FS_FreeSearch(pr_fssearchlist[i]);
3359 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3366 float search_begin(string pattern, float caseinsensitive, float quiet)
3369 void PF_search_begin(void)
3373 int caseinsens, quiet;
3375 pattern = G_STRING(OFS_PARM0);
3377 PR_CheckEmptyString(pattern);
3379 caseinsens = G_FLOAT(OFS_PARM1);
3380 quiet = G_FLOAT(OFS_PARM2);
3382 for(handle = 0; handle < MAX_SEARCHES; handle++)
3383 if(!pr_fssearchlist[handle])
3386 if(handle >= MAX_SEARCHES)
3388 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3389 G_FLOAT(OFS_RETURN) = -2;
3393 if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3394 G_FLOAT(OFS_RETURN) = -1;
3396 G_FLOAT(OFS_RETURN) = handle;
3403 void search_end(float handle)
3406 void PF_search_end(void)
3410 handle = G_FLOAT(OFS_PARM0);
3412 if(handle < 0 || handle >= MAX_SEARCHES)
3414 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3417 if(pr_fssearchlist[handle] == NULL)
3419 Con_Printf("PF_search_end: no such handle %i\n", handle);
3423 FS_FreeSearch(pr_fssearchlist[handle]);
3424 pr_fssearchlist[handle] = NULL;
3431 float search_getsize(float handle)
3434 void PF_search_getsize(void)
3438 handle = G_FLOAT(OFS_PARM0);
3440 if(handle < 0 || handle >= MAX_SEARCHES)
3442 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3445 if(pr_fssearchlist[handle] == NULL)
3447 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3451 G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3456 VM_search_getfilename
3458 string search_getfilename(float handle, float num)
3461 void PF_search_getfilename(void)
3463 int handle, filenum;
3466 handle = G_FLOAT(OFS_PARM0);
3467 filenum = G_FLOAT(OFS_PARM1);
3469 if(handle < 0 || handle >= MAX_SEARCHES)
3471 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3474 if(pr_fssearchlist[handle] == NULL)
3476 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3479 if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3481 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3485 tmp = PR_GetTempString();
3486 strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3488 G_INT(OFS_RETURN) = PR_SetString(tmp);
3491 void PF_cvar_string (void)
3497 str = G_STRING(OFS_PARM0);
3498 var = Cvar_FindVar (str);
3501 tmp = PR_GetTempString();
3502 strcpy(tmp, var->string);
3506 G_INT(OFS_RETURN) = PR_SetString(tmp);
3509 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
3510 void PF_dropclient (void)
3513 client_t *oldhostclient;
3514 clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3515 if (clientnum < 0 || clientnum >= svs.maxclients)
3516 PF_WARNING("dropclient: not a client\n");
3517 if (!svs.clients[clientnum].active)
3518 PF_WARNING("dropclient: that client slot is not connected\n");
3519 oldhostclient = host_client;
3520 host_client = svs.clients + clientnum;
3521 SV_DropClient(false);
3522 host_client = oldhostclient;
3525 //entity() spawnclient (DP_SV_BOTCLIENT)
3526 void PF_spawnclient (void)
3530 pr_xfunction->builtinsprofile += 2;
3532 for (i = 0;i < svs.maxclients;i++)
3534 if (!svs.clients[i].active)
3536 pr_xfunction->builtinsprofile += 100;
3537 SV_ConnectClient (i, NULL);
3538 ed = EDICT_NUM(i + 1);
3545 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
3546 void PF_clienttype (void)
3549 clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3550 if (clientnum < 0 || clientnum >= svs.maxclients)
3551 G_FLOAT(OFS_RETURN) = 3;
3552 else if (!svs.clients[clientnum].active)
3553 G_FLOAT(OFS_RETURN) = 0;
3554 else if (svs.clients[clientnum].netconnection)
3555 G_FLOAT(OFS_RETURN) = 1;
3557 G_FLOAT(OFS_RETURN) = 2;
3560 builtin_t pr_builtin[] =
3563 PF_makevectors, // #1 void(entity e) makevectors
3564 PF_setorigin, // #2 void(entity e, vector o) setorigin
3565 PF_setmodel, // #3 void(entity e, string m) setmodel
3566 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
3567 NULL, // #5 void(entity e, vector min, vector max) setabssize
3568 PF_break, // #6 void() break
3569 PF_random, // #7 float() random
3570 PF_sound, // #8 void(entity e, float chan, string samp) sound
3571 PF_normalize, // #9 vector(vector v) normalize
3572 PF_error, // #10 void(string e) error
3573 PF_objerror, // #11 void(string e) objerror
3574 PF_vlen, // #12 float(vector v) vlen
3575 PF_vectoyaw, // #13 float(vector v) vectoyaw
3576 PF_Spawn, // #14 entity() spawn
3577 PF_Remove, // #15 void(entity e) remove
3578 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3579 PF_checkclient, // #17 entity() clientlist
3580 PF_Find, // #18 entity(entity start, .string fld, string match) find
3581 PF_precache_sound, // #19 void(string s) precache_sound
3582 PF_precache_model, // #20 void(string s) precache_model
3583 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3584 PF_findradius, // #22 entity(vector org, float rad) findradius
3585 PF_bprint, // #23 void(string s) bprint
3586 PF_sprint, // #24 void(entity client, string s) sprint
3587 PF_dprint, // #25 void(string s) dprint
3588 PF_ftos, // #26 void(string s) ftos
3589 PF_vtos, // #27 void(string s) vtos
3590 PF_coredump, // #28 void() coredump
3591 PF_traceon, // #29 void() traceon
3592 PF_traceoff, // #30 void() traceoff
3593 PF_eprint, // #31 void(entity e) eprint
3594 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3596 PF_droptofloor, // #34 float() droptofloor
3597 PF_lightstyle, // #35 void(float style, string value) lightstyle
3598 PF_rint, // #36 float(float v) rint
3599 PF_floor, // #37 float(float v) floor
3600 PF_ceil, // #38 float(float v) ceil
3602 PF_checkbottom, // #40 float(entity e) checkbottom
3603 PF_pointcontents, // #41 float(vector v) pointcontents
3605 PF_fabs, // #43 float(float f) fabs
3606 PF_aim, // #44 vector(entity e, float speed) aim
3607 PF_cvar, // #45 float(string s) cvar
3608 PF_localcmd, // #46 void(string s) localcmd
3609 PF_nextent, // #47 entity(entity e) nextent
3610 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3611 PF_changeyaw, // #49 void() ChangeYaw
3613 PF_vectoangles, // #51 vector(vector v) vectoangles
3614 PF_WriteByte, // #52 void(float to, float f) WriteByte
3615 PF_WriteChar, // #53 void(float to, float f) WriteChar
3616 PF_WriteShort, // #54 void(float to, float f) WriteShort
3617 PF_WriteLong, // #55 void(float to, float f) WriteLong
3618 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3619 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3620 PF_WriteString, // #58 void(float to, string s) WriteString
3621 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3622 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3623 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3624 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3625 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3626 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3627 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3629 SV_MoveToGoal, // #67 void(float step) movetogoal
3630 PF_precache_file, // #68 string(string s) precache_file
3631 PF_makestatic, // #69 void(entity e) makestatic
3632 PF_changelevel, // #70 void(string s) changelevel
3634 PF_cvar_set, // #72 void(string var, string val) cvar_set
3635 PF_centerprint, // #73 void(entity client, strings) centerprint
3636 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3637 PF_precache_model, // #75 string(string s) precache_model2
3638 PF_precache_sound, // #76 string(string s) precache_sound2
3639 PF_precache_file, // #77 string(string s) precache_file2
3640 PF_setspawnparms, // #78 void(entity e) setspawnparms
3643 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3652 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3653 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3654 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3655 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3656 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3657 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3658 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3659 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3660 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3661 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3672 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3673 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3674 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3675 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3676 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3677 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3678 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3679 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3680 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3681 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3682 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3683 a a a a a a a a // #120-199
3684 a a a a a a a a a a // #200-299
3685 a a a a a a a a a a // #300-399
3686 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3687 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3688 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3689 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3690 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3691 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3692 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3693 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3694 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3695 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3696 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3697 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3698 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3699 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3700 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3701 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3702 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3703 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3704 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3705 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3706 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3707 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3708 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3709 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3710 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3711 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3712 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3713 PF_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3714 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3715 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3716 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3717 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3718 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3719 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3720 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3721 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3722 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3723 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3724 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3725 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3726 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3727 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3728 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3729 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3730 PF_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3731 PF_search_end, // #445 void(float handle) search_end (DP_FS_SEARCH)
3732 PF_search_getsize, // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3733 PF_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3734 PF_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3735 PF_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3736 PF_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3737 PF_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3738 PF_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3739 PF_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3740 PF_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3741 PF_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3746 a a a a // #460-499 (LordHavoc)
3749 builtin_t *pr_builtins = pr_builtin;
3750 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3752 void PR_Cmd_Init(void)
3754 pr_strings_mempool = Mem_AllocPool("pr_stringszone", 0, NULL);
3759 void PR_Cmd_Reset(void)
3761 Mem_EmptyPool(pr_strings_mempool);
3763 PR_Files_CloseAll();