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 #define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
27 ===============================================================================
31 ===============================================================================
34 char *PF_VarString (int first)
40 for (i=first ; i<pr_argc ; i++)
42 strcat (out, G_STRING((OFS_PARM0+i*3)));
47 char *QSG_EXTENSIONS = "\
85 qboolean checkextension(char *name)
90 for (e = QSG_EXTENSIONS;*e;e++)
92 if (!*e || e[len] == ' ' && !strnicmp(e, name, len))
94 while (*e && *e != ' ')
106 returns true if the extension is supported by the server
108 checkextension(extensionname)
111 void PF_checkextension (void)
113 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
120 This is a TERMINAL error, which will kill off the entire server.
132 Con_Printf ("======SERVER ERROR in %s:\n%s\n"
133 ,pr_strings + pr_xfunction->s_name,s);
134 ed = PROG_TO_EDICT(pr_global_struct->self);
137 Host_Error ("Program error");
144 Dumps out self, then an error message. The program is aborted and self is
145 removed, but the level can continue.
150 void PF_objerror (void)
156 Con_Printf ("======OBJECT ERROR in %s:\n%s\n"
157 ,pr_strings + pr_xfunction->s_name,s);
158 ed = PROG_TO_EDICT(pr_global_struct->self);
162 Host_Error ("Program error");
171 Writes new values for v_forward, v_up, and v_right based on angles
175 void PF_makevectors (void)
177 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
184 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.
186 setorigin (entity, origin)
189 void PF_setorigin (void)
194 e = G_EDICT(OFS_PARM0);
195 org = G_VECTOR(OFS_PARM1);
196 VectorCopy (org, e->v.origin);
197 SV_LinkEdict (e, false);
201 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
206 float xvector[2], yvector[2];
208 vec3_t base, transformed;
211 for (i=0 ; i<3 ; i++)
213 PR_RunError ("backwards mins/maxs");
215 rotate = false; // FIXME: implement rotation properly again
219 VectorCopy (min, rmin);
220 VectorCopy (max, rmax);
224 // find min / max for rotations
225 angles = e->v.angles;
227 a = angles[1]/180 * M_PI;
231 yvector[0] = -sin(a);
234 VectorCopy (min, bounds[0]);
235 VectorCopy (max, bounds[1]);
237 rmin[0] = rmin[1] = rmin[2] = 9999;
238 rmax[0] = rmax[1] = rmax[2] = -9999;
240 for (i=0 ; i<= 1 ; i++)
242 base[0] = bounds[i][0];
243 for (j=0 ; j<= 1 ; j++)
245 base[1] = bounds[j][1];
246 for (k=0 ; k<= 1 ; k++)
248 base[2] = bounds[k][2];
250 // transform the point
251 transformed[0] = xvector[0]*base[0] + yvector[0]*base[1];
252 transformed[1] = xvector[1]*base[0] + yvector[1]*base[1];
253 transformed[2] = base[2];
255 for (l=0 ; l<3 ; l++)
257 if (transformed[l] < rmin[l])
258 rmin[l] = transformed[l];
259 if (transformed[l] > rmax[l])
260 rmax[l] = transformed[l];
267 // set derived values
268 VectorCopy (rmin, e->v.mins);
269 VectorCopy (rmax, e->v.maxs);
270 VectorSubtract (max, min, e->v.size);
272 SV_LinkEdict (e, false);
279 the size box is rotated by the current angle
281 setsize (entity, minvector, maxvector)
284 void PF_setsize (void)
289 e = G_EDICT(OFS_PARM0);
290 min = G_VECTOR(OFS_PARM1);
291 max = G_VECTOR(OFS_PARM2);
292 SetMinMaxSize (e, min, max, false);
300 setmodel(entity, model)
303 void PF_setmodel (void)
310 e = G_EDICT(OFS_PARM0);
311 m = G_STRING(OFS_PARM1);
313 // check to see if model was properly precached
314 for (i=0, check = sv.model_precache ; *check ; i++, check++)
315 if (!strcmp(*check, m))
319 PR_RunError ("no precache: %s\n", m);
322 e->v.model = m - pr_strings;
323 e->v.modelindex = i; //SV_ModelIndex (m);
325 mod = sv.models[ (int)e->v.modelindex]; // Mod_ForName (m, true);
329 { // LordHavoc: corrected model bounding box, but for compatibility that means I have to break it here
331 if (mod->type == ALIASTYPE_MDL)
333 min[0] = min[1] = min[2] = -16;
334 max[0] = max[1] = max[2] = 16;
335 SetMinMaxSize (e, min, max, true);
338 SetMinMaxSize (e, mod->mins, mod->maxs, true);
341 SetMinMaxSize (e, mod->mins, mod->maxs, true);
343 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
350 broadcast print to everyone on server
355 void PF_bprint (void)
360 SV_BroadcastPrintf ("%s", s);
367 single print to a specific client
369 sprint(clientent, value)
372 void PF_sprint (void)
378 entnum = G_EDICTNUM(OFS_PARM0);
381 if (entnum < 1 || entnum > svs.maxclients)
383 Con_Printf ("tried to sprint to a non-client\n");
387 client = &svs.clients[entnum-1];
389 MSG_WriteChar (&client->message,svc_print);
390 MSG_WriteString (&client->message, s );
398 single print to a specific client
400 centerprint(clientent, value)
403 void PF_centerprint (void)
409 entnum = G_EDICTNUM(OFS_PARM0);
412 if (entnum < 1 || entnum > svs.maxclients)
414 Con_Printf ("tried to sprint to a non-client\n");
418 client = &svs.clients[entnum-1];
420 MSG_WriteChar (&client->message,svc_centerprint);
421 MSG_WriteString (&client->message, s );
429 vector normalize(vector)
432 void PF_normalize (void)
438 value1 = G_VECTOR(OFS_PARM0);
440 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
444 newvalue[0] = newvalue[1] = newvalue[2] = 0;
448 newvalue[0] = value1[0] * new;
449 newvalue[1] = value1[1] * new;
450 newvalue[2] = value1[2] * new;
453 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
468 value1 = G_VECTOR(OFS_PARM0);
470 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
473 G_FLOAT(OFS_RETURN) = new;
480 float vectoyaw(vector)
483 void PF_vectoyaw (void)
488 value1 = G_VECTOR(OFS_PARM0);
490 if (value1[1] == 0 && value1[0] == 0)
494 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
499 G_FLOAT(OFS_RETURN) = yaw;
507 vector vectoangles(vector)
510 void PF_vectoangles (void)
516 value1 = G_VECTOR(OFS_PARM0);
518 if (value1[1] == 0 && value1[0] == 0)
528 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
532 forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
533 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
538 G_FLOAT(OFS_RETURN+0) = pitch;
539 G_FLOAT(OFS_RETURN+1) = yaw;
540 G_FLOAT(OFS_RETURN+2) = 0;
547 Returns a number from 0<= num < 1
552 void PF_random (void)
556 num = (rand ()&0x7fff) / ((float)0x7fff);
558 G_FLOAT(OFS_RETURN) = num;
565 particle(origin, color, count)
568 void PF_particle (void)
574 org = G_VECTOR(OFS_PARM0);
575 dir = G_VECTOR(OFS_PARM1);
576 color = G_FLOAT(OFS_PARM2);
577 count = G_FLOAT(OFS_PARM3);
578 SV_StartParticle (org, dir, color, count);
588 void PF_ambientsound (void)
593 float vol, attenuation;
596 pos = G_VECTOR (OFS_PARM0);
597 samp = G_STRING(OFS_PARM1);
598 vol = G_FLOAT(OFS_PARM2);
599 attenuation = G_FLOAT(OFS_PARM3);
601 // check to see if samp was properly precached
602 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
603 if (!strcmp(*check,samp))
608 Con_Printf ("no precache: %s\n", samp);
612 // add an svc_spawnambient command to the level signon packet
614 MSG_WriteByte (&sv.signon,svc_spawnstaticsound);
615 for (i=0 ; i<3 ; i++)
616 MSG_WriteCoord(&sv.signon, pos[i]);
618 MSG_WriteByte (&sv.signon, soundnum);
620 MSG_WriteByte (&sv.signon, vol*255);
621 MSG_WriteByte (&sv.signon, attenuation*64);
629 Each entity can have eight independant sound sources, like voice,
632 Channel 0 is an auto-allocate channel, the others override anything
633 allready running on that entity/channel pair.
635 An attenuation of 0 will play full volume everywhere in the level.
636 Larger attenuations will drop off.
648 entity = G_EDICT(OFS_PARM0);
649 channel = G_FLOAT(OFS_PARM1);
650 sample = G_STRING(OFS_PARM2);
651 volume = G_FLOAT(OFS_PARM3) * 255;
652 attenuation = G_FLOAT(OFS_PARM4);
654 if (volume < 0 || volume > 255)
655 Sys_Error ("SV_StartSound: volume = %i", volume);
657 if (attenuation < 0 || attenuation > 4)
658 Sys_Error ("SV_StartSound: attenuation = %f", attenuation);
660 if (channel < 0 || channel > 7)
661 Sys_Error ("SV_StartSound: channel = %i", channel);
663 SV_StartSound (entity, channel, sample, volume, attenuation);
675 Con_Printf ("break statement\n");
676 *(int *)-4 = 0; // dump to debugger
677 // PR_RunError ("break statement");
684 Used for use tracing and shot targeting
685 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
686 if the tryents flag is set.
688 traceline (vector1, vector2, tryents)
691 void PF_traceline (void)
698 v1 = G_VECTOR(OFS_PARM0);
699 v2 = G_VECTOR(OFS_PARM1);
700 nomonsters = G_FLOAT(OFS_PARM2);
701 ent = G_EDICT(OFS_PARM3);
703 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
705 pr_global_struct->trace_allsolid = trace.allsolid;
706 pr_global_struct->trace_startsolid = trace.startsolid;
707 pr_global_struct->trace_fraction = trace.fraction;
708 pr_global_struct->trace_inwater = trace.inwater;
709 pr_global_struct->trace_inopen = trace.inopen;
710 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
711 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
712 pr_global_struct->trace_plane_dist = trace.plane.dist;
714 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
716 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
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 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
731 // LordHavoc: added this for my own use, VERY useful, similar to traceline
732 void PF_tracebox (void)
734 float *v1, *v2, *m1, *m2;
739 v1 = G_VECTOR(OFS_PARM0);
740 m1 = G_VECTOR(OFS_PARM1);
741 m2 = G_VECTOR(OFS_PARM2);
742 v2 = G_VECTOR(OFS_PARM3);
743 nomonsters = G_FLOAT(OFS_PARM4);
744 ent = G_EDICT(OFS_PARM5);
746 trace = SV_Move (v1, m1, m2, v2, nomonsters, ent);
748 pr_global_struct->trace_allsolid = trace.allsolid;
749 pr_global_struct->trace_startsolid = trace.startsolid;
750 pr_global_struct->trace_fraction = trace.fraction;
751 pr_global_struct->trace_inwater = trace.inwater;
752 pr_global_struct->trace_inopen = trace.inopen;
753 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
754 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
755 pr_global_struct->trace_plane_dist = trace.plane.dist;
757 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
759 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
762 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
763 void PF_TraceToss (void)
769 ent = G_EDICT(OFS_PARM0);
770 ignore = G_EDICT(OFS_PARM1);
772 trace = SV_Trace_Toss (ent, ignore);
774 pr_global_struct->trace_allsolid = trace.allsolid;
775 pr_global_struct->trace_startsolid = trace.startsolid;
776 pr_global_struct->trace_fraction = trace.fraction;
777 pr_global_struct->trace_inwater = trace.inwater;
778 pr_global_struct->trace_inopen = trace.inopen;
779 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
780 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
781 pr_global_struct->trace_plane_dist = trace.plane.dist;
783 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
785 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
793 Returns true if the given entity can move to the given position from it's
794 current position by walking or rolling.
796 scalar checkpos (entity, vector)
799 void PF_checkpos (void)
803 //============================================================================
805 byte checkpvs[MAX_MAP_LEAFS/8];
807 int PF_newcheckclient (int check)
815 // cycle to the next one
819 if (check > svs.maxclients)
820 check = svs.maxclients;
822 if (check == svs.maxclients)
829 if (i == svs.maxclients+1)
835 break; // didn't find anything else
839 if (ent->v.health <= 0)
841 if ((int)ent->v.flags & FL_NOTARGET)
844 // anything that is a client, or has a client as an enemy
848 // get the PVS for the entity
849 VectorAdd (ent->v.origin, ent->v.view_ofs, org);
850 leaf = Mod_PointInLeaf (org, sv.worldmodel);
851 pvs = Mod_LeafPVS (leaf, sv.worldmodel);
852 memcpy (checkpvs, pvs, (sv.worldmodel->numleafs+7)>>3 );
861 Returns a client (or object that has a client enemy) that would be a
864 If there are more than one valid options, they are cycled each frame
866 If (self.origin + self.viewofs) is not in the PVS of the current target,
867 it is not returned at all.
873 int c_invis, c_notvis;
874 void PF_checkclient (void)
881 // find a new check if on a new frame
882 if (sv.time - sv.lastchecktime >= 0.1)
884 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
885 sv.lastchecktime = sv.time;
888 // return check if it might be visible
889 ent = EDICT_NUM(sv.lastcheck);
890 if (ent->free || ent->v.health <= 0)
892 RETURN_EDICT(sv.edicts);
896 // if current entity can't possibly see the check entity, return 0
897 self = PROG_TO_EDICT(pr_global_struct->self);
898 VectorAdd (self->v.origin, self->v.view_ofs, view);
899 leaf = Mod_PointInLeaf (view, sv.worldmodel);
900 l = (leaf - sv.worldmodel->leafs) - 1;
901 if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
904 RETURN_EDICT(sv.edicts);
908 // might be able to see it
913 //============================================================================
920 Sends text over to the client's execution buffer
922 stuffcmd (clientent, value)
925 void PF_stuffcmd (void)
931 entnum = G_EDICTNUM(OFS_PARM0);
932 if (entnum < 1 || entnum > svs.maxclients)
933 PR_RunError ("Parm 0 not a client");
934 str = G_STRING(OFS_PARM1);
937 host_client = &svs.clients[entnum-1];
938 Host_ClientCommands ("%s", str);
946 Sends text over to the client's execution buffer
951 void PF_localcmd (void)
955 str = G_STRING(OFS_PARM0);
970 str = G_STRING(OFS_PARM0);
972 G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
982 void PF_cvar_set (void)
986 var = G_STRING(OFS_PARM0);
987 val = G_STRING(OFS_PARM1);
996 Returns a chain of entities that have origins within a spherical area
998 findradius (origin, radius)
1001 void PF_findradius (void)
1003 edict_t *ent, *chain;
1009 chain = (edict_t *)sv.edicts;
1011 org = G_VECTOR(OFS_PARM0);
1012 rad = G_FLOAT(OFS_PARM1);
1014 ent = NEXT_EDICT(sv.edicts);
1015 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1019 if (ent->v.solid == SOLID_NOT)
1021 for (j=0 ; j<3 ; j++)
1022 eorg[j] = org[j] - (ent->v.origin[j] + (ent->v.mins[j] + ent->v.maxs[j])*0.5);
1023 if (Length(eorg) > rad)
1026 ent->v.chain = EDICT_TO_PROG(chain);
1030 RETURN_EDICT(chain);
1039 void PF_dprint (void)
1041 Con_DPrintf ("%s",PF_VarString(0));
1044 char pr_string_temp[128];
1049 v = G_FLOAT(OFS_PARM0);
1051 // LordHavoc: ftos improvement
1052 sprintf (pr_string_temp, "%g", v);
1055 sprintf (pr_string_temp, "%d",(int)v);
1057 sprintf (pr_string_temp, "%5.1f",v);
1059 G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
1065 v = G_FLOAT(OFS_PARM0);
1066 G_FLOAT(OFS_RETURN) = fabs(v);
1071 sprintf (pr_string_temp, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1072 G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
1077 sprintf (pr_string_temp, "entity %i", G_EDICTNUM(OFS_PARM0));
1078 G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
1081 void PF_Spawn (void)
1088 void PF_Remove (void)
1092 ed = G_EDICT(OFS_PARM0);
1097 // entity (entity start, .string field, string match) find = #5;
1105 e = G_EDICTNUM(OFS_PARM0);
1106 f = G_INT(OFS_PARM1);
1107 s = G_STRING(OFS_PARM2);
1109 PR_RunError ("PF_Find: bad search string");
1111 for (e++ ; e < sv.num_edicts ; e++)
1126 RETURN_EDICT(sv.edicts);
1129 // LordHavoc: added this for searching float, int, and entity reference fields
1130 void PF_FindFloat (void)
1137 e = G_EDICTNUM(OFS_PARM0);
1138 f = G_INT(OFS_PARM1);
1139 s = G_FLOAT(OFS_PARM2);
1141 for (e++ ; e < sv.num_edicts ; e++)
1146 if (E_FLOAT(ed,f) == s)
1153 RETURN_EDICT(sv.edicts);
1156 void PR_CheckEmptyString (char *s)
1159 PR_RunError ("Bad string");
1162 void PF_precache_file (void)
1163 { // precache_file is only used to copy files with qcc, it does nothing
1164 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1167 void PF_precache_sound (void)
1172 if (sv.state != ss_loading)
1173 PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
1175 s = G_STRING(OFS_PARM0);
1176 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1177 PR_CheckEmptyString (s);
1179 for (i=0 ; i<MAX_SOUNDS ; i++)
1181 if (!sv.sound_precache[i])
1183 sv.sound_precache[i] = s;
1186 if (!strcmp(sv.sound_precache[i], s))
1189 PR_RunError ("PF_precache_sound: overflow");
1193 void PF_precache_model (void)
1198 if (sv.state != ss_loading)
1199 PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
1201 s = G_STRING(OFS_PARM0);
1202 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1203 PR_CheckEmptyString (s);
1205 for (i=0 ; i<MAX_MODELS ; i++)
1207 if (!sv.model_precache[i])
1209 sv.model_precache[i] = s;
1212 sv.models[i] = Mod_ForName (s, true);
1217 if (!strcmp(sv.model_precache[i], s))
1220 PR_RunError ("PF_precache_model: overflow");
1224 void PF_coredump (void)
1229 void PF_traceon (void)
1234 void PF_traceoff (void)
1239 void PF_eprint (void)
1241 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1248 float(float yaw, float dist) walkmove
1251 void PF_walkmove (void)
1259 ent = PROG_TO_EDICT(pr_global_struct->self);
1260 yaw = G_FLOAT(OFS_PARM0);
1261 dist = G_FLOAT(OFS_PARM1);
1263 if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1265 G_FLOAT(OFS_RETURN) = 0;
1269 yaw = yaw*M_PI*2 / 360;
1271 move[0] = cos(yaw)*dist;
1272 move[1] = sin(yaw)*dist;
1275 // save program state, because SV_movestep may call other progs
1276 oldf = pr_xfunction;
1277 oldself = pr_global_struct->self;
1279 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1282 // restore program state
1283 pr_xfunction = oldf;
1284 pr_global_struct->self = oldself;
1294 void PF_droptofloor (void)
1300 ent = PROG_TO_EDICT(pr_global_struct->self);
1302 VectorCopy (ent->v.origin, end);
1305 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
1307 if (trace.fraction == 1 || trace.allsolid)
1308 G_FLOAT(OFS_RETURN) = 0;
1311 VectorCopy (trace.endpos, ent->v.origin);
1312 SV_LinkEdict (ent, false);
1313 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1314 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1315 G_FLOAT(OFS_RETURN) = 1;
1323 void(float style, string value) lightstyle
1326 void PF_lightstyle (void)
1333 style = G_FLOAT(OFS_PARM0);
1334 val = G_STRING(OFS_PARM1);
1336 // change the string in sv
1337 sv.lightstyles[style] = val;
1339 // send message to all clients on this server
1340 if (sv.state != ss_active)
1343 for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
1344 if (client->active || client->spawned)
1346 MSG_WriteChar (&client->message, svc_lightstyle);
1347 MSG_WriteChar (&client->message,style);
1348 MSG_WriteString (&client->message, val);
1355 f = G_FLOAT(OFS_PARM0);
1357 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1359 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1361 void PF_floor (void)
1363 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1367 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1376 void PF_checkbottom (void)
1378 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1386 void PF_pointcontents (void)
1388 G_FLOAT(OFS_RETURN) = SV_PointContents (G_VECTOR(OFS_PARM0));
1395 entity nextent(entity)
1398 void PF_nextent (void)
1403 i = G_EDICTNUM(OFS_PARM0);
1407 if (i == sv.num_edicts)
1409 RETURN_EDICT(sv.edicts);
1425 Pick a vector for the player to shoot along
1426 vector aim(entity, missilespeed)
1429 cvar_t sv_aim = {"sv_aim", "0.93"};
1432 edict_t *ent, *check, *bestent;
1433 vec3_t start, dir, end, bestdir;
1436 float dist, bestdist;
1439 ent = G_EDICT(OFS_PARM0);
1440 speed = G_FLOAT(OFS_PARM1);
1442 VectorCopy (ent->v.origin, start);
1445 // try sending a trace straight
1446 VectorCopy (pr_global_struct->v_forward, dir);
1447 VectorMA (start, 2048, dir, end);
1448 tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
1449 if (tr.ent && tr.ent->v.takedamage == DAMAGE_AIM
1450 && (!teamplay.value || ent->v.team <=0 || ent->v.team != tr.ent->v.team) )
1452 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1457 // try all possible entities
1458 VectorCopy (dir, bestdir);
1459 bestdist = sv_aim.value;
1462 check = NEXT_EDICT(sv.edicts);
1463 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1465 if (check->v.takedamage != DAMAGE_AIM)
1469 if (teamplay.value && ent->v.team > 0 && ent->v.team == check->v.team)
1470 continue; // don't aim at teammate
1471 for (j=0 ; j<3 ; j++)
1472 end[j] = check->v.origin[j]
1473 + 0.5*(check->v.mins[j] + check->v.maxs[j]);
1474 VectorSubtract (end, start, dir);
1475 VectorNormalize (dir);
1476 dist = DotProduct (dir, pr_global_struct->v_forward);
1477 if (dist < bestdist)
1478 continue; // to far to turn
1479 tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
1480 if (tr.ent == check)
1481 { // can shoot at this one
1489 VectorSubtract (bestent->v.origin, ent->v.origin, dir);
1490 dist = DotProduct (dir, pr_global_struct->v_forward);
1491 VectorScale (pr_global_struct->v_forward, dist, end);
1493 VectorNormalize (end);
1494 VectorCopy (end, G_VECTOR(OFS_RETURN));
1498 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1506 This was a major timewaster in progs, so it was converted to C
1509 void PF_changeyaw (void)
1512 float ideal, current, move, speed;
1514 ent = PROG_TO_EDICT(pr_global_struct->self);
1515 current = anglemod( ent->v.angles[1] );
1516 ideal = ent->v.ideal_yaw;
1517 speed = ent->v.yaw_speed;
1519 if (current == ideal)
1521 move = ideal - current;
1522 if (ideal > current)
1543 ent->v.angles[1] = anglemod (current + move);
1551 void PF_changepitch (void)
1554 float ideal, current, move, speed;
1557 ent = G_EDICT(OFS_PARM0);
1558 current = anglemod( ent->v.angles[0] );
1559 if (val = GETEDICTFIELDVALUE(ent, eval_idealpitch))
1560 ideal = val->_float;
1563 PR_RunError ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1566 if (val = GETEDICTFIELDVALUE(ent, eval_pitch_speed))
1567 speed = val->_float;
1570 PR_RunError ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1574 if (current == ideal)
1576 move = ideal - current;
1577 if (ideal > current)
1598 ent->v.angles[0] = anglemod (current + move);
1602 ===============================================================================
1606 ===============================================================================
1609 #define MSG_BROADCAST 0 // unreliable to all
1610 #define MSG_ONE 1 // reliable to one (msg_entity)
1611 #define MSG_ALL 2 // reliable to all
1612 #define MSG_INIT 3 // write to the init string
1614 sizebuf_t *WriteDest (void)
1620 dest = G_FLOAT(OFS_PARM0);
1624 return &sv.datagram;
1627 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1628 entnum = NUM_FOR_EDICT(ent);
1629 if (entnum < 1 || entnum > svs.maxclients)
1630 PR_RunError ("WriteDest: not a client");
1631 return &svs.clients[entnum-1].message;
1634 return &sv.reliable_datagram;
1640 PR_RunError ("WriteDest: bad destination");
1647 void PF_WriteByte (void)
1649 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1652 void PF_WriteChar (void)
1654 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1657 void PF_WriteShort (void)
1659 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1662 void PF_WriteLong (void)
1664 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1667 void PF_WriteAngle (void)
1669 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1672 void PF_WriteCoord (void)
1674 MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1677 void PF_WriteString (void)
1679 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1683 void PF_WriteEntity (void)
1685 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1688 //=============================================================================
1690 int SV_ModelIndex (char *name);
1692 void PF_makestatic (void)
1697 ent = G_EDICT(OFS_PARM0);
1699 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1701 MSG_WriteByte (&sv.signon, SV_ModelIndex(pr_strings + ent->v.model));
1703 MSG_WriteByte (&sv.signon, ent->v.frame);
1704 MSG_WriteByte (&sv.signon, ent->v.colormap);
1705 MSG_WriteByte (&sv.signon, ent->v.skin);
1706 for (i=0 ; i<3 ; i++)
1708 MSG_WriteCoord(&sv.signon, ent->v.origin[i]);
1709 MSG_WriteAngle(&sv.signon, ent->v.angles[i]);
1712 // throw the entity away now
1716 //=============================================================================
1723 void PF_setspawnparms (void)
1729 ent = G_EDICT(OFS_PARM0);
1730 i = NUM_FOR_EDICT(ent);
1731 if (i < 1 || i > svs.maxclients)
1732 PR_RunError ("Entity is not a client");
1734 // copy spawn parms out of the client_t
1735 client = svs.clients + (i-1);
1737 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1738 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1746 void PF_changelevel (void)
1750 // make sure we don't issue two changelevels
1751 if (svs.changelevel_issued)
1753 svs.changelevel_issued = true;
1755 s = G_STRING(OFS_PARM0);
1756 Cbuf_AddText (va("changelevel %s\n",s));
1761 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1766 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1771 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1778 Returns a vector of length < 1
1783 void PF_randomvec (void)
1788 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1789 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1790 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1792 while (DotProduct(temp, temp) >= 1);
1793 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1796 void SV_LightPoint (vec3_t color, vec3_t p);
1801 Returns a color vector indicating the lighting at the requested point.
1803 (Internal Operation note: actually measures the light beneath the point, just like
1804 the model lighting on the client)
1809 void PF_GetLight (void)
1813 p = G_VECTOR(OFS_PARM0);
1814 SV_LightPoint (color, p);
1815 VectorCopy (color, G_VECTOR(OFS_RETURN));
1818 #define MAX_QC_CVARS 128
1819 cvar_t qc_cvar[MAX_QC_CVARS];
1822 void PF_registercvar (void)
1826 name = G_STRING(OFS_PARM1);
1827 value = G_STRING(OFS_PARM2);
1828 G_FLOAT(OFS_RETURN) = 0;
1829 // first check to see if it has allready been defined
1830 if (Cvar_FindVar (name))
1833 // check for overlap with a command
1834 if (Cmd_Exists (name))
1836 Con_Printf ("PF_registercvar: %s is a command\n", name);
1840 if (currentqc_cvar >= MAX_QC_CVARS)
1841 PR_RunError ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1843 // copy the name and value
1844 variable = &qc_cvar[currentqc_cvar++];
1845 variable->name = Z_Malloc (strlen(name)+1);
1846 strcpy (variable->name, name);
1847 variable->string = Z_Malloc (strlen(value)+1);
1848 strcpy (variable->string, value);
1849 variable->value = atof (value);
1851 // link the variable in
1852 variable->next = cvar_vars;
1853 cvar_vars = variable;
1854 G_FLOAT(OFS_RETURN) = 1; // success
1861 returns the minimum of two supplied floats
1868 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1870 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1871 else if (pr_argc >= 3)
1874 float f = G_FLOAT(OFS_PARM0);
1875 for (i = 1;i < pr_argc;i++)
1876 if (G_FLOAT((OFS_PARM0+i*3)) < f)
1877 f = G_FLOAT((OFS_PARM0+i*3));
1878 G_FLOAT(OFS_RETURN) = f;
1881 PR_RunError("min: must supply at least 2 floats\n");
1888 returns the maximum of two supplied floats
1895 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1897 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1898 else if (pr_argc >= 3)
1901 float f = G_FLOAT(OFS_PARM0);
1902 for (i = 1;i < pr_argc;i++)
1903 if (G_FLOAT((OFS_PARM0+i*3)) > f)
1904 f = G_FLOAT((OFS_PARM0+i*3));
1905 G_FLOAT(OFS_RETURN) = f;
1908 PR_RunError("max: must supply at least 2 floats\n");
1915 returns number bounded by supplied range
1917 min(min, value, max)
1920 void PF_bound (void)
1922 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
1929 returns a raised to power b
1936 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1939 void PF_Fixme (void)
1941 PR_RunError ("unimplemented builtin"); // LordHavoc: was misspelled (bulitin)
1946 builtin_t pr_builtin[] =
1949 PF_makevectors, // void(entity e) makevectors = #1;
1950 PF_setorigin, // void(entity e, vector o) setorigin = #2;
1951 PF_setmodel, // void(entity e, string m) setmodel = #3;
1952 PF_setsize, // void(entity e, vector min, vector max) setsize = #4;
1953 PF_Fixme, // void(entity e, vector min, vector max) setabssize = #5;
1954 PF_break, // void() break = #6;
1955 PF_random, // float() random = #7;
1956 PF_sound, // void(entity e, float chan, string samp) sound = #8;
1957 PF_normalize, // vector(vector v) normalize = #9;
1958 PF_error, // void(string e) error = #10;
1959 PF_objerror, // void(string e) objerror = #11;
1960 PF_vlen, // float(vector v) vlen = #12;
1961 PF_vectoyaw, // float(vector v) vectoyaw = #13;
1962 PF_Spawn, // entity() spawn = #14;
1963 PF_Remove, // void(entity e) remove = #15;
1964 PF_traceline, // float(vector v1, vector v2, float tryents) traceline = #16;
1965 PF_checkclient, // entity() clientlist = #17;
1966 PF_Find, // entity(entity start, .string fld, string match) find = #18;
1967 PF_precache_sound, // void(string s) precache_sound = #19;
1968 PF_precache_model, // void(string s) precache_model = #20;
1969 PF_stuffcmd, // void(entity client, string s)stuffcmd = #21;
1970 PF_findradius, // entity(vector org, float rad) findradius = #22;
1971 PF_bprint, // void(string s) bprint = #23;
1972 PF_sprint, // void(entity client, string s) sprint = #24;
1973 PF_dprint, // void(string s) dprint = #25;
1974 PF_ftos, // void(string s) ftos = #26;
1975 PF_vtos, // void(string s) vtos = #27;
1979 PF_eprint, // void(entity e) debug print an entire entity
1980 PF_walkmove, // float(float yaw, float dist) walkmove
1981 PF_Fixme, // float(float yaw, float dist) walkmove
2031 PF_precache_sound, // precache_sound2 is different only for qcc
2036 PF_Fixme, // #79 LordHavoc: dunno who owns 79-89, so these are just padding
2048 PF_tracebox, // #90 LordHavoc builtin range (9x)
2049 PF_randomvec, // #91
2051 PF_registercvar, // #93
2056 PF_FindFloat, // #98
2057 PF_checkextension // #99
2060 builtin_t *pr_builtins = pr_builtin;
2061 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);