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 = "\
86 qboolean checkextension(char *name)
91 for (e = QSG_EXTENSIONS;*e;e++)
97 if (!strncasecmp(e, name, len))
99 while (*e && *e != ' ')
109 returns true if the extension is supported by the server
111 checkextension(extensionname)
114 void PF_checkextension (void)
116 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
123 This is a TERMINAL error, which will kill off the entire server.
135 Con_Printf ("======SERVER ERROR in %s:\n%s\n"
136 ,pr_strings + pr_xfunction->s_name,s);
137 ed = PROG_TO_EDICT(pr_global_struct->self);
140 Host_Error ("Program error");
147 Dumps out self, then an error message. The program is aborted and self is
148 removed, but the level can continue.
153 void PF_objerror (void)
159 Con_Printf ("======OBJECT ERROR in %s:\n%s\n"
160 ,pr_strings + pr_xfunction->s_name,s);
161 ed = PROG_TO_EDICT(pr_global_struct->self);
165 Host_Error ("Program error");
174 Writes new values for v_forward, v_up, and v_right based on angles
178 void PF_makevectors (void)
180 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
187 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.
189 setorigin (entity, origin)
192 void PF_setorigin (void)
197 e = G_EDICT(OFS_PARM0);
198 org = G_VECTOR(OFS_PARM1);
199 VectorCopy (org, e->v.origin);
200 SV_LinkEdict (e, false);
204 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
209 float xvector[2], yvector[2];
211 vec3_t base, transformed;
214 for (i=0 ; i<3 ; i++)
216 PR_RunError ("backwards mins/maxs");
218 rotate = false; // FIXME: implement rotation properly again
222 VectorCopy (min, rmin);
223 VectorCopy (max, rmax);
227 // find min / max for rotations
228 angles = e->v.angles;
230 a = angles[1]/180 * M_PI;
234 yvector[0] = -sin(a);
237 VectorCopy (min, bounds[0]);
238 VectorCopy (max, bounds[1]);
240 rmin[0] = rmin[1] = rmin[2] = 9999;
241 rmax[0] = rmax[1] = rmax[2] = -9999;
243 for (i=0 ; i<= 1 ; i++)
245 base[0] = bounds[i][0];
246 for (j=0 ; j<= 1 ; j++)
248 base[1] = bounds[j][1];
249 for (k=0 ; k<= 1 ; k++)
251 base[2] = bounds[k][2];
253 // transform the point
254 transformed[0] = xvector[0]*base[0] + yvector[0]*base[1];
255 transformed[1] = xvector[1]*base[0] + yvector[1]*base[1];
256 transformed[2] = base[2];
258 for (l=0 ; l<3 ; l++)
260 if (transformed[l] < rmin[l])
261 rmin[l] = transformed[l];
262 if (transformed[l] > rmax[l])
263 rmax[l] = transformed[l];
270 // set derived values
271 VectorCopy (rmin, e->v.mins);
272 VectorCopy (rmax, e->v.maxs);
273 VectorSubtract (max, min, e->v.size);
275 SV_LinkEdict (e, false);
282 the size box is rotated by the current angle
284 setsize (entity, minvector, maxvector)
287 void PF_setsize (void)
292 e = G_EDICT(OFS_PARM0);
293 min = G_VECTOR(OFS_PARM1);
294 max = G_VECTOR(OFS_PARM2);
295 SetMinMaxSize (e, min, max, false);
303 setmodel(entity, model)
306 void PF_setmodel (void)
313 e = G_EDICT(OFS_PARM0);
314 m = G_STRING(OFS_PARM1);
316 // check to see if model was properly precached
317 for (i=0, check = sv.model_precache ; *check ; i++, check++)
318 if (!strcmp(*check, m))
322 PR_RunError ("no precache: %s\n", m);
325 e->v.model = m - pr_strings;
326 e->v.modelindex = i; //SV_ModelIndex (m);
328 mod = sv.models[ (int)e->v.modelindex]; // Mod_ForName (m, true);
332 { // LordHavoc: corrected model bounding box, but for compatibility that means I have to break it here
334 if (mod->type == ALIASTYPE_MDL)
336 min[0] = min[1] = min[2] = -16;
337 max[0] = max[1] = max[2] = 16;
338 SetMinMaxSize (e, min, max, true);
341 SetMinMaxSize (e, mod->mins, mod->maxs, true);
344 SetMinMaxSize (e, mod->mins, mod->maxs, true);
346 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
353 broadcast print to everyone on server
358 void PF_bprint (void)
363 SV_BroadcastPrintf ("%s", s);
370 single print to a specific client
372 sprint(clientent, value)
375 void PF_sprint (void)
381 entnum = G_EDICTNUM(OFS_PARM0);
384 if (entnum < 1 || entnum > svs.maxclients)
386 Con_Printf ("tried to sprint to a non-client\n");
390 client = &svs.clients[entnum-1];
392 MSG_WriteChar (&client->message,svc_print);
393 MSG_WriteString (&client->message, s );
401 single print to a specific client
403 centerprint(clientent, value)
406 void PF_centerprint (void)
412 entnum = G_EDICTNUM(OFS_PARM0);
415 if (entnum < 1 || entnum > svs.maxclients)
417 Con_Printf ("tried to sprint to a non-client\n");
421 client = &svs.clients[entnum-1];
423 MSG_WriteChar (&client->message,svc_centerprint);
424 MSG_WriteString (&client->message, s );
432 vector normalize(vector)
435 void PF_normalize (void)
441 value1 = G_VECTOR(OFS_PARM0);
443 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
447 newvalue[0] = newvalue[1] = newvalue[2] = 0;
451 newvalue[0] = value1[0] * new;
452 newvalue[1] = value1[1] * new;
453 newvalue[2] = value1[2] * new;
456 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
471 value1 = G_VECTOR(OFS_PARM0);
473 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
476 G_FLOAT(OFS_RETURN) = new;
483 float vectoyaw(vector)
486 void PF_vectoyaw (void)
491 value1 = G_VECTOR(OFS_PARM0);
493 if (value1[1] == 0 && value1[0] == 0)
497 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
502 G_FLOAT(OFS_RETURN) = yaw;
510 vector vectoangles(vector)
513 void PF_vectoangles (void)
519 value1 = G_VECTOR(OFS_PARM0);
521 if (value1[1] == 0 && value1[0] == 0)
531 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
535 forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
536 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
541 G_FLOAT(OFS_RETURN+0) = pitch;
542 G_FLOAT(OFS_RETURN+1) = yaw;
543 G_FLOAT(OFS_RETURN+2) = 0;
550 Returns a number from 0<= num < 1
555 void PF_random (void)
559 num = (rand ()&0x7fff) / ((float)0x7fff);
561 G_FLOAT(OFS_RETURN) = num;
568 particle(origin, color, count)
571 void PF_particle (void)
577 org = G_VECTOR(OFS_PARM0);
578 dir = G_VECTOR(OFS_PARM1);
579 color = G_FLOAT(OFS_PARM2);
580 count = G_FLOAT(OFS_PARM3);
581 SV_StartParticle (org, dir, color, count);
591 void PF_ambientsound (void)
596 float vol, attenuation;
599 pos = G_VECTOR (OFS_PARM0);
600 samp = G_STRING(OFS_PARM1);
601 vol = G_FLOAT(OFS_PARM2);
602 attenuation = G_FLOAT(OFS_PARM3);
604 // check to see if samp was properly precached
605 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
606 if (!strcmp(*check,samp))
611 Con_Printf ("no precache: %s\n", samp);
615 // add an svc_spawnambient command to the level signon packet
617 MSG_WriteByte (&sv.signon,svc_spawnstaticsound);
618 for (i=0 ; i<3 ; i++)
619 MSG_WriteFloatCoord(&sv.signon, pos[i]);
621 MSG_WriteByte (&sv.signon, soundnum);
623 MSG_WriteByte (&sv.signon, vol*255);
624 MSG_WriteByte (&sv.signon, attenuation*64);
632 Each entity can have eight independant sound sources, like voice,
635 Channel 0 is an auto-allocate channel, the others override anything
636 allready running on that entity/channel pair.
638 An attenuation of 0 will play full volume everywhere in the level.
639 Larger attenuations will drop off.
651 entity = G_EDICT(OFS_PARM0);
652 channel = G_FLOAT(OFS_PARM1);
653 sample = G_STRING(OFS_PARM2);
654 volume = G_FLOAT(OFS_PARM3) * 255;
655 attenuation = G_FLOAT(OFS_PARM4);
657 if (volume < 0 || volume > 255)
658 Host_Error ("SV_StartSound: volume = %i", volume);
660 if (attenuation < 0 || attenuation > 4)
661 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
663 if (channel < 0 || channel > 7)
664 Host_Error ("SV_StartSound: channel = %i", channel);
666 SV_StartSound (entity, channel, sample, volume, attenuation);
678 Con_Printf ("break statement\n");
679 *(int *)-4 = 0; // dump to debugger
680 // PR_RunError ("break statement");
687 Used for use tracing and shot targeting
688 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
689 if the tryents flag is set.
691 traceline (vector1, vector2, tryents)
694 void PF_traceline (void)
701 v1 = G_VECTOR(OFS_PARM0);
702 v2 = G_VECTOR(OFS_PARM1);
703 nomonsters = G_FLOAT(OFS_PARM2);
704 ent = G_EDICT(OFS_PARM3);
706 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
708 pr_global_struct->trace_allsolid = trace.allsolid;
709 pr_global_struct->trace_startsolid = trace.startsolid;
710 pr_global_struct->trace_fraction = trace.fraction;
711 pr_global_struct->trace_inwater = trace.inwater;
712 pr_global_struct->trace_inopen = trace.inopen;
713 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
714 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
715 pr_global_struct->trace_plane_dist = trace.plane.dist;
717 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
719 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
727 Used for use tracing and shot targeting
728 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
729 if the tryents flag is set.
731 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
734 // LordHavoc: added this for my own use, VERY useful, similar to traceline
735 void PF_tracebox (void)
737 float *v1, *v2, *m1, *m2;
742 v1 = G_VECTOR(OFS_PARM0);
743 m1 = G_VECTOR(OFS_PARM1);
744 m2 = G_VECTOR(OFS_PARM2);
745 v2 = G_VECTOR(OFS_PARM3);
746 nomonsters = G_FLOAT(OFS_PARM4);
747 ent = G_EDICT(OFS_PARM5);
749 trace = SV_Move (v1, m1, m2, v2, nomonsters, ent);
751 pr_global_struct->trace_allsolid = trace.allsolid;
752 pr_global_struct->trace_startsolid = trace.startsolid;
753 pr_global_struct->trace_fraction = trace.fraction;
754 pr_global_struct->trace_inwater = trace.inwater;
755 pr_global_struct->trace_inopen = trace.inopen;
756 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
757 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
758 pr_global_struct->trace_plane_dist = trace.plane.dist;
760 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
762 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
765 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
766 void PF_TraceToss (void)
772 ent = G_EDICT(OFS_PARM0);
773 ignore = G_EDICT(OFS_PARM1);
775 trace = SV_Trace_Toss (ent, ignore);
777 pr_global_struct->trace_allsolid = trace.allsolid;
778 pr_global_struct->trace_startsolid = trace.startsolid;
779 pr_global_struct->trace_fraction = trace.fraction;
780 pr_global_struct->trace_inwater = trace.inwater;
781 pr_global_struct->trace_inopen = trace.inopen;
782 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
783 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
784 pr_global_struct->trace_plane_dist = trace.plane.dist;
786 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
788 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
796 Returns true if the given entity can move to the given position from it's
797 current position by walking or rolling.
799 scalar checkpos (entity, vector)
802 void PF_checkpos (void)
806 //============================================================================
808 byte checkpvs[MAX_MAP_LEAFS/8];
810 int PF_newcheckclient (int check)
818 // cycle to the next one
822 if (check > svs.maxclients)
823 check = svs.maxclients;
825 if (check == svs.maxclients)
832 if (i == svs.maxclients+1)
838 break; // didn't find anything else
842 if (ent->v.health <= 0)
844 if ((int)ent->v.flags & FL_NOTARGET)
847 // anything that is a client, or has a client as an enemy
851 // get the PVS for the entity
852 VectorAdd (ent->v.origin, ent->v.view_ofs, org);
853 leaf = Mod_PointInLeaf (org, sv.worldmodel);
854 pvs = Mod_LeafPVS (leaf, sv.worldmodel);
855 memcpy (checkpvs, pvs, (sv.worldmodel->numleafs+7)>>3 );
864 Returns a client (or object that has a client enemy) that would be a
867 If there are more than one valid options, they are cycled each frame
869 If (self.origin + self.viewofs) is not in the PVS of the current target,
870 it is not returned at all.
876 int c_invis, c_notvis;
877 void PF_checkclient (void)
884 // find a new check if on a new frame
885 if (sv.time - sv.lastchecktime >= 0.1)
887 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
888 sv.lastchecktime = sv.time;
891 // return check if it might be visible
892 ent = EDICT_NUM(sv.lastcheck);
893 if (ent->free || ent->v.health <= 0)
895 RETURN_EDICT(sv.edicts);
899 // if current entity can't possibly see the check entity, return 0
900 self = PROG_TO_EDICT(pr_global_struct->self);
901 VectorAdd (self->v.origin, self->v.view_ofs, view);
902 leaf = Mod_PointInLeaf (view, sv.worldmodel);
903 l = (leaf - sv.worldmodel->leafs) - 1;
904 if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
907 RETURN_EDICT(sv.edicts);
911 // might be able to see it
916 //============================================================================
923 Sends text over to the client's execution buffer
925 stuffcmd (clientent, value)
928 void PF_stuffcmd (void)
934 entnum = G_EDICTNUM(OFS_PARM0);
935 if (entnum < 1 || entnum > svs.maxclients)
936 PR_RunError ("Parm 0 not a client");
937 str = G_STRING(OFS_PARM1);
940 host_client = &svs.clients[entnum-1];
941 Host_ClientCommands ("%s", str);
949 Sends text over to the client's execution buffer
954 void PF_localcmd (void)
958 str = G_STRING(OFS_PARM0);
973 str = G_STRING(OFS_PARM0);
975 G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
985 void PF_cvar_set (void)
989 var = G_STRING(OFS_PARM0);
990 val = G_STRING(OFS_PARM1);
999 Returns a chain of entities that have origins within a spherical area
1001 findradius (origin, radius)
1004 void PF_findradius (void)
1006 edict_t *ent, *chain;
1012 chain = (edict_t *)sv.edicts;
1014 org = G_VECTOR(OFS_PARM0);
1015 rad = G_FLOAT(OFS_PARM1);
1017 ent = NEXT_EDICT(sv.edicts);
1018 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1022 if (ent->v.solid == SOLID_NOT)
1024 for (j=0 ; j<3 ; j++)
1025 eorg[j] = org[j] - (ent->v.origin[j] + (ent->v.mins[j] + ent->v.maxs[j])*0.5);
1026 if (Length(eorg) > rad)
1029 ent->v.chain = EDICT_TO_PROG(chain);
1033 RETURN_EDICT(chain);
1042 void PF_dprint (void)
1044 Con_DPrintf ("%s",PF_VarString(0));
1047 char pr_string_temp[128];
1052 v = G_FLOAT(OFS_PARM0);
1054 // LordHavoc: ftos improvement
1055 sprintf (pr_string_temp, "%g", v);
1058 sprintf (pr_string_temp, "%d",(int)v);
1060 sprintf (pr_string_temp, "%5.1f",v);
1062 G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
1068 v = G_FLOAT(OFS_PARM0);
1069 G_FLOAT(OFS_RETURN) = fabs(v);
1074 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]);
1075 G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
1080 sprintf (pr_string_temp, "entity %i", G_EDICTNUM(OFS_PARM0));
1081 G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
1084 void PF_Spawn (void)
1091 void PF_Remove (void)
1095 ed = G_EDICT(OFS_PARM0);
1100 // entity (entity start, .string field, string match) find = #5;
1108 e = G_EDICTNUM(OFS_PARM0);
1109 f = G_INT(OFS_PARM1);
1110 s = G_STRING(OFS_PARM2);
1112 PR_RunError ("PF_Find: bad search string");
1114 for (e++ ; e < sv.num_edicts ; e++)
1129 RETURN_EDICT(sv.edicts);
1132 // LordHavoc: added this for searching float, int, and entity reference fields
1133 void PF_FindFloat (void)
1140 e = G_EDICTNUM(OFS_PARM0);
1141 f = G_INT(OFS_PARM1);
1142 s = G_FLOAT(OFS_PARM2);
1144 for (e++ ; e < sv.num_edicts ; e++)
1149 if (E_FLOAT(ed,f) == s)
1156 RETURN_EDICT(sv.edicts);
1159 void PR_CheckEmptyString (char *s)
1162 PR_RunError ("Bad string");
1165 void PF_precache_file (void)
1166 { // precache_file is only used to copy files with qcc, it does nothing
1167 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1170 void PF_precache_sound (void)
1175 if (sv.state != ss_loading)
1176 PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
1178 s = G_STRING(OFS_PARM0);
1179 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1180 PR_CheckEmptyString (s);
1182 for (i=0 ; i<MAX_SOUNDS ; i++)
1184 if (!sv.sound_precache[i])
1186 sv.sound_precache[i] = s;
1189 if (!strcmp(sv.sound_precache[i], s))
1192 PR_RunError ("PF_precache_sound: overflow");
1196 void PF_precache_model (void)
1201 if (sv.state != ss_loading)
1202 PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
1204 s = G_STRING(OFS_PARM0);
1205 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1206 PR_CheckEmptyString (s);
1208 for (i=0 ; i<MAX_MODELS ; i++)
1210 if (!sv.model_precache[i])
1212 sv.model_precache[i] = s;
1215 sv.models[i] = Mod_ForName (s, true);
1220 if (!strcmp(sv.model_precache[i], s))
1223 PR_RunError ("PF_precache_model: overflow");
1227 void PF_coredump (void)
1232 void PF_traceon (void)
1237 void PF_traceoff (void)
1242 void PF_eprint (void)
1244 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1251 float(float yaw, float dist) walkmove
1254 void PF_walkmove (void)
1262 ent = PROG_TO_EDICT(pr_global_struct->self);
1263 yaw = G_FLOAT(OFS_PARM0);
1264 dist = G_FLOAT(OFS_PARM1);
1266 if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1268 G_FLOAT(OFS_RETURN) = 0;
1272 yaw = yaw*M_PI*2 / 360;
1274 move[0] = cos(yaw)*dist;
1275 move[1] = sin(yaw)*dist;
1278 // save program state, because SV_movestep may call other progs
1279 oldf = pr_xfunction;
1280 oldself = pr_global_struct->self;
1282 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1285 // restore program state
1286 pr_xfunction = oldf;
1287 pr_global_struct->self = oldself;
1297 void PF_droptofloor (void)
1303 ent = PROG_TO_EDICT(pr_global_struct->self);
1305 VectorCopy (ent->v.origin, end);
1308 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
1310 if (trace.fraction == 1 || trace.allsolid)
1311 G_FLOAT(OFS_RETURN) = 0;
1314 VectorCopy (trace.endpos, ent->v.origin);
1315 SV_LinkEdict (ent, false);
1316 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1317 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1318 G_FLOAT(OFS_RETURN) = 1;
1326 void(float style, string value) lightstyle
1329 void PF_lightstyle (void)
1336 style = G_FLOAT(OFS_PARM0);
1337 val = G_STRING(OFS_PARM1);
1339 // change the string in sv
1340 sv.lightstyles[style] = val;
1342 // send message to all clients on this server
1343 if (sv.state != ss_active)
1346 for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
1347 if (client->active || client->spawned)
1349 MSG_WriteChar (&client->message, svc_lightstyle);
1350 MSG_WriteChar (&client->message,style);
1351 MSG_WriteString (&client->message, val);
1358 f = G_FLOAT(OFS_PARM0);
1360 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1362 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1364 void PF_floor (void)
1366 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1370 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1379 void PF_checkbottom (void)
1381 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1389 void PF_pointcontents (void)
1391 G_FLOAT(OFS_RETURN) = SV_PointContents (G_VECTOR(OFS_PARM0));
1398 entity nextent(entity)
1401 void PF_nextent (void)
1406 i = G_EDICTNUM(OFS_PARM0);
1410 if (i == sv.num_edicts)
1412 RETURN_EDICT(sv.edicts);
1428 Pick a vector for the player to shoot along
1429 vector aim(entity, missilespeed)
1432 cvar_t sv_aim = {"sv_aim", "0.93"};
1435 edict_t *ent, *check, *bestent;
1436 vec3_t start, dir, end, bestdir;
1439 float dist, bestdist;
1442 ent = G_EDICT(OFS_PARM0);
1443 speed = G_FLOAT(OFS_PARM1);
1445 VectorCopy (ent->v.origin, start);
1448 // try sending a trace straight
1449 VectorCopy (pr_global_struct->v_forward, dir);
1450 VectorMA (start, 2048, dir, end);
1451 tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
1452 if (tr.ent && tr.ent->v.takedamage == DAMAGE_AIM
1453 && (!teamplay.value || ent->v.team <=0 || ent->v.team != tr.ent->v.team) )
1455 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1460 // try all possible entities
1461 VectorCopy (dir, bestdir);
1462 bestdist = sv_aim.value;
1465 check = NEXT_EDICT(sv.edicts);
1466 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1468 if (check->v.takedamage != DAMAGE_AIM)
1472 if (teamplay.value && ent->v.team > 0 && ent->v.team == check->v.team)
1473 continue; // don't aim at teammate
1474 for (j=0 ; j<3 ; j++)
1475 end[j] = check->v.origin[j]
1476 + 0.5*(check->v.mins[j] + check->v.maxs[j]);
1477 VectorSubtract (end, start, dir);
1478 VectorNormalize (dir);
1479 dist = DotProduct (dir, pr_global_struct->v_forward);
1480 if (dist < bestdist)
1481 continue; // to far to turn
1482 tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
1483 if (tr.ent == check)
1484 { // can shoot at this one
1492 VectorSubtract (bestent->v.origin, ent->v.origin, dir);
1493 dist = DotProduct (dir, pr_global_struct->v_forward);
1494 VectorScale (pr_global_struct->v_forward, dist, end);
1496 VectorNormalize (end);
1497 VectorCopy (end, G_VECTOR(OFS_RETURN));
1501 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1509 This was a major timewaster in progs, so it was converted to C
1512 void PF_changeyaw (void)
1515 float ideal, current, move, speed;
1517 ent = PROG_TO_EDICT(pr_global_struct->self);
1518 current = anglemod( ent->v.angles[1] );
1519 ideal = ent->v.ideal_yaw;
1520 speed = ent->v.yaw_speed;
1522 if (current == ideal)
1524 move = ideal - current;
1525 if (ideal > current)
1546 ent->v.angles[1] = anglemod (current + move);
1554 void PF_changepitch (void)
1557 float ideal, current, move, speed;
1560 ent = G_EDICT(OFS_PARM0);
1561 current = anglemod( ent->v.angles[0] );
1562 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1563 ideal = val->_float;
1566 PR_RunError ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1569 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1570 speed = val->_float;
1573 PR_RunError ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1577 if (current == ideal)
1579 move = ideal - current;
1580 if (ideal > current)
1601 ent->v.angles[0] = anglemod (current + move);
1605 ===============================================================================
1609 ===============================================================================
1612 #define MSG_BROADCAST 0 // unreliable to all
1613 #define MSG_ONE 1 // reliable to one (msg_entity)
1614 #define MSG_ALL 2 // reliable to all
1615 #define MSG_INIT 3 // write to the init string
1617 sizebuf_t *WriteDest (void)
1623 dest = G_FLOAT(OFS_PARM0);
1627 return &sv.datagram;
1630 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1631 entnum = NUM_FOR_EDICT(ent);
1632 if (entnum < 1 || entnum > svs.maxclients)
1633 PR_RunError ("WriteDest: not a client");
1634 return &svs.clients[entnum-1].message;
1637 return &sv.reliable_datagram;
1643 PR_RunError ("WriteDest: bad destination");
1650 void PF_WriteByte (void)
1652 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1655 void PF_WriteChar (void)
1657 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1660 void PF_WriteShort (void)
1662 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1665 void PF_WriteLong (void)
1667 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1670 void PF_WriteAngle (void)
1672 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1675 void PF_WriteCoord (void)
1677 MSG_WriteFloatCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1680 void PF_WriteString (void)
1682 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1686 void PF_WriteEntity (void)
1688 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1691 //=============================================================================
1693 int SV_ModelIndex (char *name);
1695 void PF_makestatic (void)
1700 ent = G_EDICT(OFS_PARM0);
1702 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1704 MSG_WriteByte (&sv.signon, SV_ModelIndex(pr_strings + ent->v.model));
1706 MSG_WriteByte (&sv.signon, ent->v.frame);
1707 MSG_WriteByte (&sv.signon, ent->v.colormap);
1708 MSG_WriteByte (&sv.signon, ent->v.skin);
1709 for (i=0 ; i<3 ; i++)
1711 MSG_WriteFloatCoord(&sv.signon, ent->v.origin[i]);
1712 MSG_WriteAngle(&sv.signon, ent->v.angles[i]);
1715 // throw the entity away now
1719 //=============================================================================
1726 void PF_setspawnparms (void)
1732 ent = G_EDICT(OFS_PARM0);
1733 i = NUM_FOR_EDICT(ent);
1734 if (i < 1 || i > svs.maxclients)
1735 PR_RunError ("Entity is not a client");
1737 // copy spawn parms out of the client_t
1738 client = svs.clients + (i-1);
1740 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1741 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1749 void PF_changelevel (void)
1753 // make sure we don't issue two changelevels
1754 if (svs.changelevel_issued)
1756 svs.changelevel_issued = true;
1758 s = G_STRING(OFS_PARM0);
1759 Cbuf_AddText (va("changelevel %s\n",s));
1764 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1769 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1774 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1781 Returns a vector of length < 1
1786 void PF_randomvec (void)
1791 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1792 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1793 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1795 while (DotProduct(temp, temp) >= 1);
1796 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1799 void SV_LightPoint (vec3_t color, vec3_t p);
1804 Returns a color vector indicating the lighting at the requested point.
1806 (Internal Operation note: actually measures the light beneath the point, just like
1807 the model lighting on the client)
1812 void PF_GetLight (void)
1816 p = G_VECTOR(OFS_PARM0);
1817 SV_LightPoint (color, p);
1818 VectorCopy (color, G_VECTOR(OFS_RETURN));
1821 #define MAX_QC_CVARS 128
1822 cvar_t qc_cvar[MAX_QC_CVARS];
1825 void PF_registercvar (void)
1829 name = G_STRING(OFS_PARM1);
1830 value = G_STRING(OFS_PARM2);
1831 G_FLOAT(OFS_RETURN) = 0;
1832 // first check to see if it has allready been defined
1833 if (Cvar_FindVar (name))
1836 // check for overlap with a command
1837 if (Cmd_Exists (name))
1839 Con_Printf ("PF_registercvar: %s is a command\n", name);
1843 if (currentqc_cvar >= MAX_QC_CVARS)
1844 PR_RunError ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1846 // copy the name and value
1847 variable = &qc_cvar[currentqc_cvar++];
1848 variable->name = Z_Malloc (strlen(name)+1);
1849 strcpy (variable->name, name);
1850 variable->string = Z_Malloc (strlen(value)+1);
1851 strcpy (variable->string, value);
1852 variable->value = atof (value);
1854 // link the variable in
1855 variable->next = cvar_vars;
1856 cvar_vars = variable;
1857 G_FLOAT(OFS_RETURN) = 1; // success
1864 returns the minimum of two supplied floats
1871 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1873 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1874 else if (pr_argc >= 3)
1877 float f = G_FLOAT(OFS_PARM0);
1878 for (i = 1;i < pr_argc;i++)
1879 if (G_FLOAT((OFS_PARM0+i*3)) < f)
1880 f = G_FLOAT((OFS_PARM0+i*3));
1881 G_FLOAT(OFS_RETURN) = f;
1884 PR_RunError("min: must supply at least 2 floats\n");
1891 returns the maximum of two supplied floats
1898 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1900 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1901 else if (pr_argc >= 3)
1904 float f = G_FLOAT(OFS_PARM0);
1905 for (i = 1;i < pr_argc;i++)
1906 if (G_FLOAT((OFS_PARM0+i*3)) > f)
1907 f = G_FLOAT((OFS_PARM0+i*3));
1908 G_FLOAT(OFS_RETURN) = f;
1911 PR_RunError("max: must supply at least 2 floats\n");
1918 returns number bounded by supplied range
1920 min(min, value, max)
1923 void PF_bound (void)
1925 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
1932 returns a raised to power b
1939 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1946 copies data from one entity to another
1948 copyentity(src, dst)
1951 void PF_copyentity (void)
1954 in = G_EDICT(OFS_PARM0);
1955 out = G_EDICT(OFS_PARM1);
1956 memcpy(out, in, pr_edict_size);
1963 sets the color of a client and broadcasts the update to all connected clients
1965 setcolor(clientent, value)
1968 void PF_setcolor (void)
1973 entnum = G_EDICTNUM(OFS_PARM0);
1974 i = G_FLOAT(OFS_PARM1);
1976 if (entnum < 1 || entnum > svs.maxclients)
1978 Con_Printf ("tried to setcolor a non-client\n");
1982 client = &svs.clients[entnum-1];
1984 client->edict->v.team = (i & 15) + 1;
1986 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1987 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
1988 MSG_WriteByte (&sv.reliable_datagram, i);
1991 void PF_Fixme (void)
1993 PR_RunError ("unimplemented builtin"); // LordHavoc: was misspelled (bulitin)
1998 builtin_t pr_builtin[] =
2001 PF_makevectors, // void(entity e) makevectors = #1;
2002 PF_setorigin, // void(entity e, vector o) setorigin = #2;
2003 PF_setmodel, // void(entity e, string m) setmodel = #3;
2004 PF_setsize, // void(entity e, vector min, vector max) setsize = #4;
2005 PF_Fixme, // void(entity e, vector min, vector max) setabssize = #5;
2006 PF_break, // void() break = #6;
2007 PF_random, // float() random = #7;
2008 PF_sound, // void(entity e, float chan, string samp) sound = #8;
2009 PF_normalize, // vector(vector v) normalize = #9;
2010 PF_error, // void(string e) error = #10;
2011 PF_objerror, // void(string e) objerror = #11;
2012 PF_vlen, // float(vector v) vlen = #12;
2013 PF_vectoyaw, // float(vector v) vectoyaw = #13;
2014 PF_Spawn, // entity() spawn = #14;
2015 PF_Remove, // void(entity e) remove = #15;
2016 PF_traceline, // float(vector v1, vector v2, float tryents) traceline = #16;
2017 PF_checkclient, // entity() clientlist = #17;
2018 PF_Find, // entity(entity start, .string fld, string match) find = #18;
2019 PF_precache_sound, // void(string s) precache_sound = #19;
2020 PF_precache_model, // void(string s) precache_model = #20;
2021 PF_stuffcmd, // void(entity client, string s)stuffcmd = #21;
2022 PF_findradius, // entity(vector org, float rad) findradius = #22;
2023 PF_bprint, // void(string s) bprint = #23;
2024 PF_sprint, // void(entity client, string s) sprint = #24;
2025 PF_dprint, // void(string s) dprint = #25;
2026 PF_ftos, // void(string s) ftos = #26;
2027 PF_vtos, // void(string s) vtos = #27;
2031 PF_eprint, // void(entity e) debug print an entire entity
2032 PF_walkmove, // float(float yaw, float dist) walkmove
2033 PF_Fixme, // float(float yaw, float dist) walkmove
2083 PF_precache_sound, // precache_sound2 is different only for qcc
2088 PF_Fixme, // #79 LordHavoc: dunno who owns 79-89, so these are just padding
2100 PF_tracebox, // #90 LordHavoc builtin range (9x)
2101 PF_randomvec, // #91
2103 PF_registercvar, // #93
2108 PF_FindFloat, // #98
2109 PF_checkextension, // #99
2110 #define a PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme,
2111 #define aa a a a a a a a a a a
2115 PF_copyentity, // #400 LordHavoc: builtin range (4xx)
2116 PF_setcolor, // #401
2119 builtin_t *pr_builtins = pr_builtin;
2120 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);