2449 lines
48 KiB
C
2449 lines
48 KiB
C
/*
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
#include "quakedef.h"
|
|
#include "menu.h"
|
|
|
|
#define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
BUILT-IN FUNCTIONS
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
char *PF_VarString (int first)
|
|
{
|
|
int i;
|
|
static char out[256];
|
|
|
|
out[0] = 0;
|
|
for (i=first ; i<pr_argc ; i++)
|
|
{
|
|
strcat (out, G_STRING((OFS_PARM0+i*3)));
|
|
}
|
|
return out;
|
|
}
|
|
|
|
char *QSG_EXTENSIONS = "\
|
|
TQ_DLIGHTS \
|
|
TQ_RAILTRAIL \
|
|
TQ_PLASMA \
|
|
TQ_SLOWMO \
|
|
DP_ENT_ALPHA \
|
|
DP_ENT_SCALE \
|
|
DP_QUAKE2_MODEL \
|
|
DP_HALFLIFE_MAP \
|
|
DP_SV_DRAWONLYTOCLIENT \
|
|
DP_SV_NODRAWTOCLIENT \
|
|
\0";
|
|
|
|
qboolean checkextension(char *name)
|
|
{
|
|
int len;
|
|
char *e;
|
|
len = strlen(name);
|
|
for (e = QSG_EXTENSIONS;*e;e++)
|
|
{
|
|
while (*e == ' ')
|
|
e++;
|
|
if (!*e)
|
|
break;
|
|
if (!Q_strncasecmp(e, name, len))
|
|
return true;
|
|
while (*e && *e != ' ')
|
|
e++;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PF_checkextension
|
|
|
|
returns true if the extension is supported by the server
|
|
|
|
checkextension(extensionname)
|
|
=================
|
|
*/
|
|
void PF_checkextension (void)
|
|
{
|
|
G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PF_errror
|
|
|
|
This is a TERMINAL error, which will kill off the entire server.
|
|
Dumps self.
|
|
|
|
error(value)
|
|
=================
|
|
*/
|
|
void PF_error (void)
|
|
{
|
|
char *s;
|
|
edict_t *ed;
|
|
|
|
s = PF_VarString(0);
|
|
Con_Printf ("======SERVER ERROR in %s:\n%s\n"
|
|
,pr_strings + pr_xfunction->s_name,s);
|
|
ed = PROG_TO_EDICT(pr_global_struct->self);
|
|
ED_Print (ed);
|
|
|
|
Host_Error ("Program error");
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PF_objerror
|
|
|
|
Dumps out self, then an error message. The program is aborted and self is
|
|
removed, but the level can continue.
|
|
|
|
objerror(value)
|
|
=================
|
|
*/
|
|
void PF_objerror (void)
|
|
{
|
|
char *s;
|
|
edict_t *ed;
|
|
|
|
s = PF_VarString(0);
|
|
Con_Printf ("======OBJECT ERROR in %s:\n%s\n"
|
|
,pr_strings + pr_xfunction->s_name,s);
|
|
ed = PROG_TO_EDICT(pr_global_struct->self);
|
|
ED_Print (ed);
|
|
ED_Free (ed);
|
|
|
|
Host_Error ("Program error");
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
==============
|
|
PF_makevectors
|
|
|
|
Writes new values for v_forward, v_up, and v_right based on angles
|
|
makevectors(vector)
|
|
==============
|
|
*/
|
|
void PF_makevectors (void)
|
|
{
|
|
AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PF_setorigin
|
|
|
|
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.
|
|
|
|
setorigin (entity, origin)
|
|
=================
|
|
*/
|
|
void PF_setorigin (void)
|
|
{
|
|
edict_t *e;
|
|
float *org;
|
|
|
|
e = G_EDICT(OFS_PARM0);
|
|
org = G_VECTOR(OFS_PARM1);
|
|
VectorCopy (org, e->v.origin);
|
|
SV_LinkEdict (e, false);
|
|
}
|
|
|
|
|
|
void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
|
|
{
|
|
float *angles;
|
|
vec3_t rmin, rmax;
|
|
float bounds[2][3];
|
|
float xvector[2], yvector[2];
|
|
float a;
|
|
vec3_t base, transformed;
|
|
int i, j, k, l;
|
|
|
|
for (i=0 ; i<3 ; i++)
|
|
if (min[i] > max[i])
|
|
PR_RunError ("backwards mins/maxs");
|
|
|
|
rotate = false; // FIXME: implement rotation properly again
|
|
|
|
if (!rotate)
|
|
{
|
|
VectorCopy (min, rmin);
|
|
VectorCopy (max, rmax);
|
|
}
|
|
else
|
|
{
|
|
// find min / max for rotations
|
|
angles = e->v.angles;
|
|
|
|
a = angles[1]/180 * M_PI;
|
|
|
|
xvector[0] = cos(a);
|
|
xvector[1] = sin(a);
|
|
yvector[0] = -sin(a);
|
|
yvector[1] = cos(a);
|
|
|
|
VectorCopy (min, bounds[0]);
|
|
VectorCopy (max, bounds[1]);
|
|
|
|
rmin[0] = rmin[1] = rmin[2] = 9999;
|
|
rmax[0] = rmax[1] = rmax[2] = -9999;
|
|
|
|
for (i=0 ; i<= 1 ; i++)
|
|
{
|
|
base[0] = bounds[i][0];
|
|
for (j=0 ; j<= 1 ; j++)
|
|
{
|
|
base[1] = bounds[j][1];
|
|
for (k=0 ; k<= 1 ; k++)
|
|
{
|
|
base[2] = bounds[k][2];
|
|
|
|
// transform the point
|
|
transformed[0] = xvector[0]*base[0] + yvector[0]*base[1];
|
|
transformed[1] = xvector[1]*base[0] + yvector[1]*base[1];
|
|
transformed[2] = base[2];
|
|
|
|
for (l=0 ; l<3 ; l++)
|
|
{
|
|
if (transformed[l] < rmin[l])
|
|
rmin[l] = transformed[l];
|
|
if (transformed[l] > rmax[l])
|
|
rmax[l] = transformed[l];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// set derived values
|
|
VectorCopy (rmin, e->v.mins);
|
|
VectorCopy (rmax, e->v.maxs);
|
|
VectorSubtract (max, min, e->v.size);
|
|
|
|
SV_LinkEdict (e, false);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PF_setsize
|
|
|
|
the size box is rotated by the current angle
|
|
|
|
setsize (entity, minvector, maxvector)
|
|
=================
|
|
*/
|
|
void PF_setsize (void)
|
|
{
|
|
edict_t *e;
|
|
float *min, *max;
|
|
|
|
e = G_EDICT(OFS_PARM0);
|
|
min = G_VECTOR(OFS_PARM1);
|
|
max = G_VECTOR(OFS_PARM2);
|
|
SetMinMaxSize (e, min, max, false);
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
PF_setmodel
|
|
|
|
setmodel(entity, model)
|
|
=================
|
|
*/
|
|
void PF_setmodel (void)
|
|
{
|
|
edict_t *e;
|
|
char *m, **check;
|
|
model_t *mod;
|
|
int i;
|
|
|
|
e = G_EDICT(OFS_PARM0);
|
|
m = G_STRING(OFS_PARM1);
|
|
|
|
if (gl_particle_fire.value)
|
|
{
|
|
if (!strcmp (m, "progs/flame.mdl"))
|
|
m = "progs/fire.mdl";
|
|
|
|
if (!strcmp (m, "progs/flame2.mdl") ||
|
|
!strcmp (m, "progs/flame3.mdl"))
|
|
m = "progs/fire2.mdl";
|
|
}
|
|
|
|
// check to see if model was properly precached
|
|
for (i=0, check = sv.model_precache ; *check ; i++, check++)
|
|
if (!strcmp(*check, m))
|
|
break;
|
|
|
|
if (!*check)
|
|
PR_RunError ("no precache: %s\n", m);
|
|
|
|
|
|
e->v.model = m - pr_strings;
|
|
e->v.modelindex = i; //SV_ModelIndex (m);
|
|
|
|
mod = sv.models[ (int)e->v.modelindex]; // Mod_ForName (m, true);
|
|
|
|
if (mod)
|
|
SetMinMaxSize (e, mod->mins, mod->maxs, true);
|
|
else
|
|
SetMinMaxSize (e, vec3_origin, vec3_origin, true);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PF_bprint
|
|
|
|
broadcast print to everyone on server
|
|
|
|
bprint(value)
|
|
=================
|
|
*/
|
|
void PF_bprint (void)
|
|
{
|
|
char *s;
|
|
|
|
s = PF_VarString(0);
|
|
SV_BroadcastPrintf ("%s", s);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PF_sprint
|
|
|
|
single print to a specific client
|
|
|
|
sprint(clientent, value)
|
|
=================
|
|
*/
|
|
void PF_sprint (void)
|
|
{
|
|
char *s;
|
|
client_t *client;
|
|
int entnum;
|
|
|
|
entnum = G_EDICTNUM(OFS_PARM0);
|
|
s = PF_VarString(1);
|
|
|
|
if (entnum < 1 || entnum > svs.maxclients)
|
|
{
|
|
Con_Printf ("tried to sprint to a non-client\n");
|
|
return;
|
|
}
|
|
|
|
client = &svs.clients[entnum-1];
|
|
|
|
MSG_WriteChar (&client->message,svc_print);
|
|
MSG_WriteString (&client->message, s );
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
PF_centerprint
|
|
|
|
single print to a specific client
|
|
|
|
centerprint(clientent, value)
|
|
=================
|
|
*/
|
|
void PF_centerprint (void)
|
|
{
|
|
char *s;
|
|
client_t *client;
|
|
int entnum;
|
|
|
|
entnum = G_EDICTNUM(OFS_PARM0);
|
|
s = PF_VarString(1);
|
|
|
|
if (entnum < 1 || entnum > svs.maxclients)
|
|
{
|
|
Con_Printf ("tried to sprint to a non-client\n");
|
|
return;
|
|
}
|
|
|
|
client = &svs.clients[entnum-1];
|
|
|
|
MSG_WriteChar (&client->message,svc_centerprint);
|
|
MSG_WriteString (&client->message, s );
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
PF_normalize
|
|
|
|
vector normalize(vector)
|
|
=================
|
|
*/
|
|
void PF_normalize (void)
|
|
{
|
|
float *value1;
|
|
vec3_t newvalue;
|
|
float new;
|
|
|
|
value1 = G_VECTOR(OFS_PARM0);
|
|
|
|
new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
|
|
new = sqrt(new);
|
|
|
|
if (new == 0)
|
|
newvalue[0] = newvalue[1] = newvalue[2] = 0;
|
|
else
|
|
{
|
|
new = 1/new;
|
|
newvalue[0] = value1[0] * new;
|
|
newvalue[1] = value1[1] * new;
|
|
newvalue[2] = value1[2] * new;
|
|
}
|
|
|
|
VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PF_vlen
|
|
|
|
scalar vlen(vector)
|
|
=================
|
|
*/
|
|
void PF_vlen (void)
|
|
{
|
|
float *value1;
|
|
float new;
|
|
|
|
value1 = G_VECTOR(OFS_PARM0);
|
|
|
|
new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
|
|
new = sqrt(new);
|
|
|
|
G_FLOAT(OFS_RETURN) = new;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PF_vectoyaw
|
|
|
|
float vectoyaw(vector)
|
|
=================
|
|
*/
|
|
void PF_vectoyaw (void)
|
|
{
|
|
float *value1;
|
|
float yaw;
|
|
|
|
value1 = G_VECTOR(OFS_PARM0);
|
|
|
|
if (value1[1] == 0 && value1[0] == 0)
|
|
yaw = 0;
|
|
else
|
|
{
|
|
yaw = (int) (atan2(value1[1], value1[0]) * 57.295779513082320); // Tomaz Speed
|
|
if (yaw < 0)
|
|
yaw += 360;
|
|
}
|
|
|
|
G_FLOAT(OFS_RETURN) = yaw;
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
PF_vectoangles
|
|
|
|
vector vectoangles(vector)
|
|
=================
|
|
*/
|
|
void PF_vectoangles (void)
|
|
{
|
|
float *value1;
|
|
float forward;
|
|
float yaw, pitch;
|
|
|
|
value1 = G_VECTOR(OFS_PARM0);
|
|
|
|
if (value1[1] == 0 && value1[0] == 0)
|
|
{
|
|
yaw = 0;
|
|
if (value1[2] > 0)
|
|
pitch = 90;
|
|
else
|
|
pitch = 270;
|
|
}
|
|
else
|
|
{
|
|
yaw = (int) (atan2(value1[1], value1[0]) * 57.295779513082320); // Tomaz Speed
|
|
if (yaw < 0)
|
|
yaw += 360;
|
|
|
|
forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
|
|
pitch = (int) (atan2(value1[2], forward) * 57.295779513082320); // Tomaz Speed
|
|
if (pitch < 0)
|
|
pitch += 360;
|
|
}
|
|
|
|
G_FLOAT(OFS_RETURN+0) = pitch;
|
|
G_FLOAT(OFS_RETURN+1) = yaw;
|
|
G_FLOAT(OFS_RETURN+2) = 0;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PF_Random
|
|
|
|
Returns a number from 0<= num < 1
|
|
|
|
random()
|
|
=================
|
|
*/
|
|
void PF_random (void)
|
|
{
|
|
float num;
|
|
|
|
num = (rand ()&0x7fff) / ((float)0x7fff);
|
|
|
|
G_FLOAT(OFS_RETURN) = num;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PF_particle
|
|
|
|
particle(origin, color, count)
|
|
=================
|
|
*/
|
|
void PF_particle (void)
|
|
{
|
|
float *org, *dir;
|
|
float color;
|
|
float count;
|
|
|
|
org = G_VECTOR(OFS_PARM0);
|
|
dir = G_VECTOR(OFS_PARM1);
|
|
color = G_FLOAT(OFS_PARM2);
|
|
count = G_FLOAT(OFS_PARM3);
|
|
SV_StartParticle (org, dir, color, count);
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
PF_ambientsound
|
|
|
|
=================
|
|
*/
|
|
void PF_ambientsound (void)
|
|
{
|
|
char **check;
|
|
char *samp;
|
|
float *pos;
|
|
float vol, attenuation;
|
|
int i, soundnum;
|
|
|
|
pos = G_VECTOR (OFS_PARM0);
|
|
samp = G_STRING(OFS_PARM1);
|
|
vol = G_FLOAT(OFS_PARM2);
|
|
attenuation = G_FLOAT(OFS_PARM3);
|
|
|
|
// check to see if samp was properly precached
|
|
for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
|
|
if (!strcmp(*check,samp))
|
|
break;
|
|
|
|
if (!*check)
|
|
{
|
|
Con_Printf ("no precache: %s\n", samp);
|
|
return;
|
|
}
|
|
|
|
// add an svc_spawnambient command to the level signon packet
|
|
|
|
MSG_WriteByte (&sv.signon,svc_spawnstaticsound);
|
|
for (i=0 ; i<3 ; i++)
|
|
MSG_WriteCoord(&sv.signon, pos[i]);
|
|
|
|
MSG_WriteByte (&sv.signon, soundnum);
|
|
|
|
MSG_WriteByte (&sv.signon, vol*255);
|
|
MSG_WriteByte (&sv.signon, attenuation*64);
|
|
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PF_sound
|
|
|
|
Each entity can have eight independant sound sources, like voice,
|
|
weapon, feet, etc.
|
|
|
|
Channel 0 is an auto-allocate channel, the others override anything
|
|
allready running on that entity/channel pair.
|
|
|
|
An attenuation of 0 will play full volume everywhere in the level.
|
|
Larger attenuations will drop off.
|
|
|
|
=================
|
|
*/
|
|
void PF_sound (void)
|
|
{
|
|
char *sample;
|
|
int channel;
|
|
edict_t *entity;
|
|
int volume;
|
|
float attenuation;
|
|
|
|
entity = G_EDICT(OFS_PARM0);
|
|
channel = G_FLOAT(OFS_PARM1);
|
|
sample = G_STRING(OFS_PARM2);
|
|
volume = G_FLOAT(OFS_PARM3) * 255;
|
|
attenuation = G_FLOAT(OFS_PARM4);
|
|
|
|
if (volume < 0 || volume > 255)
|
|
Sys_Error ("SV_StartSound: volume = %i", volume);
|
|
|
|
if (attenuation < 0 || attenuation > 4)
|
|
Sys_Error ("SV_StartSound: attenuation = %f", attenuation);
|
|
|
|
if (channel < 0 || channel > 7)
|
|
Sys_Error ("SV_StartSound: channel = %i", channel);
|
|
|
|
SV_StartSound (entity, channel, sample, volume, attenuation);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PF_break
|
|
|
|
break()
|
|
=================
|
|
*/
|
|
void PF_break (void)
|
|
{
|
|
Con_Printf ("break statement\n");
|
|
*(int *)-4 = 0; // dump to debugger
|
|
// PR_RunError ("break statement");
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PF_traceline
|
|
|
|
Used for use tracing and shot targeting
|
|
Traces are blocked by bbox and exact bsp entityes, and also slide box entities
|
|
if the tryents flag is set.
|
|
|
|
traceline (vector1, vector2, tryents)
|
|
=================
|
|
*/
|
|
void PF_traceline (void)
|
|
{
|
|
float *v1, *v2;
|
|
trace_t trace;
|
|
int nomonsters;
|
|
edict_t *ent;
|
|
|
|
v1 = G_VECTOR(OFS_PARM0);
|
|
v2 = G_VECTOR(OFS_PARM1);
|
|
nomonsters = G_FLOAT(OFS_PARM2);
|
|
ent = G_EDICT(OFS_PARM3);
|
|
|
|
trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
|
|
|
|
pr_global_struct->trace_allsolid = trace.allsolid;
|
|
pr_global_struct->trace_startsolid = trace.startsolid;
|
|
pr_global_struct->trace_fraction = trace.fraction;
|
|
pr_global_struct->trace_inwater = trace.inwater;
|
|
pr_global_struct->trace_inopen = trace.inopen;
|
|
VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
|
|
VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
|
|
pr_global_struct->trace_plane_dist = trace.plane.dist;
|
|
if (trace.ent)
|
|
pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
|
|
else
|
|
pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
|
|
}
|
|
|
|
//============================================================================
|
|
|
|
byte checkpvs[MAX_MAP_LEAFS/8];
|
|
|
|
int PF_newcheckclient (int check)
|
|
{
|
|
int i;
|
|
byte *pvs;
|
|
edict_t *ent;
|
|
mleaf_t *leaf;
|
|
vec3_t org;
|
|
|
|
// cycle to the next one
|
|
|
|
if (check < 1)
|
|
check = 1;
|
|
if (check > svs.maxclients)
|
|
check = svs.maxclients;
|
|
|
|
if (check == svs.maxclients)
|
|
i = 1;
|
|
else
|
|
i = check + 1;
|
|
|
|
for ( ; ; i++)
|
|
{
|
|
if (i == svs.maxclients+1)
|
|
i = 1;
|
|
|
|
ent = EDICT_NUM(i);
|
|
|
|
if (i == check)
|
|
break; // didn't find anything else
|
|
|
|
if (ent->free)
|
|
continue;
|
|
if (ent->v.health <= 0)
|
|
continue;
|
|
if ((int)ent->v.flags & FL_NOTARGET)
|
|
continue;
|
|
|
|
// anything that is a client, or has a client as an enemy
|
|
break;
|
|
}
|
|
|
|
// get the PVS for the entity
|
|
VectorAdd (ent->v.origin, ent->v.view_ofs, org);
|
|
leaf = Mod_PointInLeaf (org, sv.worldmodel);
|
|
pvs = Mod_LeafPVS (leaf, sv.worldmodel);
|
|
memcpy (checkpvs, pvs, (sv.worldmodel->numleafs+7)>>3 );
|
|
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PF_checkclient
|
|
|
|
Returns a client (or object that has a client enemy) that would be a
|
|
valid target.
|
|
|
|
If there are more than one valid options, they are cycled each frame
|
|
|
|
If (self.origin + self.viewofs) is not in the PVS of the current target,
|
|
it is not returned at all.
|
|
|
|
name checkclient ()
|
|
=================
|
|
*/
|
|
#define MAX_CHECK 16
|
|
int c_invis, c_notvis;
|
|
void PF_checkclient (void)
|
|
{
|
|
edict_t *ent, *self;
|
|
mleaf_t *leaf;
|
|
int l;
|
|
vec3_t view;
|
|
|
|
// find a new check if on a new frame
|
|
if (sv.time - sv.lastchecktime >= 0.1)
|
|
{
|
|
sv.lastcheck = PF_newcheckclient (sv.lastcheck);
|
|
sv.lastchecktime = sv.time;
|
|
}
|
|
|
|
// return check if it might be visible
|
|
ent = EDICT_NUM(sv.lastcheck);
|
|
if (ent->free || ent->v.health <= 0)
|
|
{
|
|
RETURN_EDICT(sv.edicts);
|
|
return;
|
|
}
|
|
|
|
// if current entity can't possibly see the check entity, return 0
|
|
self = PROG_TO_EDICT(pr_global_struct->self);
|
|
VectorAdd (self->v.origin, self->v.view_ofs, view);
|
|
leaf = Mod_PointInLeaf (view, sv.worldmodel);
|
|
l = (leaf - sv.worldmodel->leafs) - 1;
|
|
if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
|
|
{
|
|
c_notvis++;
|
|
RETURN_EDICT(sv.edicts);
|
|
return;
|
|
}
|
|
|
|
// might be able to see it
|
|
c_invis++;
|
|
RETURN_EDICT(ent);
|
|
}
|
|
|
|
//============================================================================
|
|
|
|
|
|
/*
|
|
=================
|
|
PF_stuffcmd
|
|
|
|
Sends text over to the client's execution buffer
|
|
|
|
stuffcmd (clientent, value)
|
|
=================
|
|
*/
|
|
void PF_stuffcmd (void)
|
|
{
|
|
int entnum;
|
|
char *str;
|
|
client_t *old;
|
|
|
|
entnum = G_EDICTNUM(OFS_PARM0);
|
|
if (entnum < 1 || entnum > svs.maxclients)
|
|
PR_RunError ("Parm 0 not a client");
|
|
str = G_STRING(OFS_PARM1);
|
|
|
|
old = host_client;
|
|
host_client = &svs.clients[entnum-1];
|
|
Host_ClientCommands ("%s", str);
|
|
host_client = old;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PF_localcmd
|
|
|
|
Sends text over to the client's execution buffer
|
|
|
|
localcmd (string)
|
|
=================
|
|
*/
|
|
void PF_localcmd (void)
|
|
{
|
|
char *str;
|
|
|
|
str = G_STRING(OFS_PARM0);
|
|
Cbuf_AddText (str);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PF_cvar
|
|
|
|
float cvar (string)
|
|
=================
|
|
*/
|
|
void PF_cvar (void)
|
|
{
|
|
char *str;
|
|
|
|
str = G_STRING(OFS_PARM0);
|
|
|
|
G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PF_cvar_set
|
|
|
|
float cvar (string)
|
|
=================
|
|
*/
|
|
void PF_cvar_set (void)
|
|
{
|
|
char *var, *val;
|
|
|
|
var = G_STRING(OFS_PARM0);
|
|
val = G_STRING(OFS_PARM1);
|
|
|
|
Cvar_Set (var, val);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PF_findradius
|
|
|
|
Returns a chain of entities that have origins within a spherical area
|
|
|
|
findradius (origin, radius)
|
|
=================
|
|
*/
|
|
void PF_findradius (void)
|
|
{
|
|
edict_t *ent, *chain;
|
|
float rad;
|
|
float *org;
|
|
vec3_t eorg;
|
|
int i, j;
|
|
|
|
chain = (edict_t *)sv.edicts;
|
|
|
|
org = G_VECTOR(OFS_PARM0);
|
|
rad = G_FLOAT(OFS_PARM1);
|
|
|
|
ent = NEXT_EDICT(sv.edicts);
|
|
for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
|
|
{
|
|
if (ent->free)
|
|
continue;
|
|
if (ent->v.solid == SOLID_NOT)
|
|
continue;
|
|
for (j=0 ; j<3 ; j++)
|
|
eorg[j] = org[j] - (ent->v.origin[j] + (ent->v.mins[j] + ent->v.maxs[j])*0.5);
|
|
if (Length(eorg) > rad)
|
|
continue;
|
|
|
|
ent->v.chain = EDICT_TO_PROG(chain);
|
|
chain = ent;
|
|
}
|
|
|
|
RETURN_EDICT(chain);
|
|
}
|
|
|
|
|
|
/*
|
|
=========
|
|
PF_dprint
|
|
=========
|
|
*/
|
|
void PF_dprint (void)
|
|
{
|
|
Con_DPrintf ("%s",PF_VarString(0));
|
|
}
|
|
|
|
char pr_string_temp[128];
|
|
|
|
void PF_ftos (void)
|
|
{
|
|
float v;
|
|
int i;
|
|
|
|
v = G_FLOAT(OFS_PARM0);
|
|
|
|
if (v == (int)v)
|
|
sprintf (pr_string_temp, "%d",(int)v);
|
|
else
|
|
{
|
|
sprintf (pr_string_temp, "%1f", v);
|
|
for (i=Q_strlen(pr_string_temp)-1 ; i>0 && pr_string_temp[i]=='0' && pr_string_temp[i-1]!='.' ; i--)
|
|
{
|
|
pr_string_temp[i] = 0;
|
|
}
|
|
}
|
|
G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
|
|
}
|
|
|
|
void PF_fabs (void)
|
|
{
|
|
float v;
|
|
v = G_FLOAT(OFS_PARM0);
|
|
G_FLOAT(OFS_RETURN) = fabs(v);
|
|
}
|
|
|
|
void PF_vtos (void)
|
|
{
|
|
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]);
|
|
G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
|
|
}
|
|
|
|
void PF_Spawn (void)
|
|
{
|
|
edict_t *ed;
|
|
ed = ED_Alloc();
|
|
RETURN_EDICT(ed);
|
|
}
|
|
|
|
void PF_Remove (void)
|
|
{
|
|
edict_t *ed;
|
|
|
|
ed = G_EDICT(OFS_PARM0);
|
|
ED_Free (ed);
|
|
}
|
|
|
|
|
|
// entity (entity start, .string field, string match) find = #5;
|
|
void PF_Find (void)
|
|
{
|
|
int e;
|
|
int f;
|
|
char *s, *t;
|
|
edict_t *ed;
|
|
|
|
e = G_EDICTNUM(OFS_PARM0);
|
|
f = G_INT(OFS_PARM1);
|
|
s = G_STRING(OFS_PARM2);
|
|
if (!s)
|
|
PR_RunError ("PF_Find: bad search string");
|
|
|
|
for (e++ ; e < sv.num_edicts ; e++)
|
|
{
|
|
ed = EDICT_NUM(e);
|
|
if (ed->free)
|
|
continue;
|
|
t = E_STRING(ed,f);
|
|
if (!t)
|
|
continue;
|
|
if (!strcmp(t,s))
|
|
{
|
|
RETURN_EDICT(ed);
|
|
return;
|
|
}
|
|
}
|
|
|
|
RETURN_EDICT(sv.edicts);
|
|
}
|
|
|
|
void PR_CheckEmptyString (char *s)
|
|
{
|
|
if (s[0] <= ' ')
|
|
PR_RunError ("Bad string");
|
|
}
|
|
|
|
//begin new image precaching / loading code -Xsniper
|
|
|
|
//new global variables
|
|
int qc_current; //current item in array
|
|
float qc_num_img; // if this gets close to MAX_QC_IMAGES then deny new ones
|
|
float qc_x[MAX_QC_IMAGES]; // x coordinate for image
|
|
float qc_y[MAX_QC_IMAGES]; // y coordinate for image
|
|
float qc_mode[MAX_QC_IMAGES]; // draw mode data, 0 for center screen, 1 for coord
|
|
char *qcimg[MAX_QC_IMAGES]; // paths to images
|
|
float qc_num_string; // number of strings on screen
|
|
float qc_sx[MAX_QC_IMAGES]; // x coordinate for string
|
|
float qc_sy[MAX_QC_IMAGES]; // y coordinate for string
|
|
char *qcstring[MAX_QC_IMAGES]; // string to be drawn to screen
|
|
|
|
void QC_Draw (void)
|
|
{
|
|
int i, j;
|
|
qpic_t *p;
|
|
|
|
//initialize i and j
|
|
i = 0;
|
|
j = qc_num_img;
|
|
|
|
//do images first
|
|
while (i < j)
|
|
{
|
|
//set up the pic
|
|
p = Draw_CachePic (qcimg[i]);
|
|
|
|
//draw based on qc_mode
|
|
if (qc_mode[i] == 0) //draw center
|
|
Draw_Pic(((vid.width - p->width)>>1),((vid.height - p->height)>>1), p);
|
|
else //draw coord
|
|
Draw_Pic(qc_x[i],qc_y[i],p);
|
|
|
|
//increment i
|
|
i = i + 1;
|
|
}
|
|
|
|
//reset i and j
|
|
i = 0;
|
|
j = qc_num_string;
|
|
|
|
//now draw text on top of the images
|
|
while (i < j)
|
|
{
|
|
//draw the text at the specified x and y coordinate
|
|
Draw_String (qc_sx[i], qc_sy[i], qcstring[i], 0);
|
|
|
|
//increment i
|
|
i = i + 1;
|
|
}
|
|
}
|
|
|
|
void PF_CoordPrint (void)
|
|
{
|
|
//make sure we haven't loaded more than MAX_QC_IMAGES
|
|
if (qc_num_string >= MAX_QC_IMAGES)
|
|
PR_RunError ("PF_CoordPrint: Too Many Strings!");
|
|
|
|
//set qc_current equal to the first parameter
|
|
qc_current = G_FLOAT(OFS_PARM0);
|
|
|
|
//set qc_x and qc_y equal to parameter 2 and 3
|
|
qc_sx[qc_current] = G_FLOAT(OFS_PARM1);
|
|
qc_sy[qc_current] = G_FLOAT(OFS_PARM2);
|
|
|
|
//set qcimg equal to the fourth parameter
|
|
qcstring[qc_current] = G_STRING(OFS_PARM3);
|
|
|
|
//increment qc_num_string
|
|
qc_num_string = qc_num_string + 1;
|
|
}
|
|
|
|
void PF_draw_coord (void)
|
|
{
|
|
//make sure we haven't loaded more than MAX_QC_IMAGES
|
|
if (qc_num_img >= MAX_QC_IMAGES)
|
|
PR_RunError ("PF_draw_coord: Too Many Images!");
|
|
|
|
//set qc_current equal to the first parameter
|
|
qc_current = G_FLOAT(OFS_PARM0);
|
|
|
|
//set qc_mode to 1
|
|
qc_mode[qc_current] = 1;
|
|
|
|
//set qc_x and qc_y equal to parameter 2 and 3
|
|
qc_x[qc_current] = G_FLOAT(OFS_PARM1);
|
|
qc_y[qc_current] = G_FLOAT(OFS_PARM2);
|
|
|
|
//set qcimg equal to the fourth parameter
|
|
qcimg[qc_current] = G_STRING(OFS_PARM3);
|
|
|
|
//increment qc_num_img
|
|
qc_num_img = qc_num_img + 1;
|
|
}
|
|
|
|
void PF_draw_center (void)
|
|
{
|
|
//make sure we haven't loaded more than MAX_QC_IMAGES
|
|
if (qc_num_img >= MAX_QC_IMAGES)
|
|
PR_RunError ("PF_draw_center: Too Many Images!");
|
|
|
|
//set qc_current equal to the first parameter
|
|
qc_current = G_FLOAT(OFS_PARM0);
|
|
|
|
//set qc_mode to 0
|
|
qc_mode[qc_current] = 0;
|
|
|
|
//set qcimg equal to the second parameter
|
|
qcimg[qc_current] = G_STRING(OFS_PARM1);
|
|
|
|
//increment qc_num_img
|
|
qc_num_img = qc_num_img + 1;
|
|
}
|
|
|
|
/*
|
|
========================
|
|
PF_init_draw
|
|
|
|
Turns on QC Image drawing mode.
|
|
All images stored in array qcimg will appear on screen.
|
|
All text stored in array qcstring will appear on screen.
|
|
========================
|
|
*/
|
|
void PF_init_draw (void)
|
|
{
|
|
//turn on QC Image drawing mode
|
|
qc_image = 1;
|
|
}
|
|
|
|
/*
|
|
========================
|
|
PF_stop_draw
|
|
|
|
Turns off QC Image drawing mode.
|
|
========================
|
|
*/
|
|
void PF_stop_draw (void)
|
|
{
|
|
int i, j;
|
|
|
|
//turn off QC Image drawing mode
|
|
qc_image = 0;
|
|
|
|
//need to reset our variables
|
|
|
|
//initialize i and j
|
|
i = 0;
|
|
j = qc_num_img;
|
|
|
|
//reset images first
|
|
while (i < j)
|
|
{
|
|
//reset qc_mode
|
|
qc_mode[i] = 0;
|
|
|
|
//reset qc_x and qc_y
|
|
qc_x[i] = 0;
|
|
qc_y[i] = 0;
|
|
|
|
//reset qcimg
|
|
qcimg[i] = "";
|
|
|
|
//increment i
|
|
i = i + 1;
|
|
}
|
|
|
|
//reset i and j
|
|
i = 0;
|
|
j = qc_num_string;
|
|
|
|
//now reset strings
|
|
while (i < j)
|
|
{
|
|
//reset qc_sx and qc_sy
|
|
qc_sx[i] = 0;
|
|
qc_sy[i] = 0;
|
|
|
|
//reset qcstring
|
|
qcstring[i] = "";
|
|
|
|
//increment i
|
|
i = i + 1;
|
|
}
|
|
|
|
//reset qc_num_img
|
|
qc_num_img = 0;
|
|
|
|
//reset qc_num_string
|
|
qc_num_string = 0;
|
|
}
|
|
|
|
//end new image precaching / loading code -Xsniper
|
|
|
|
//HUD Draw System
|
|
//new global variables
|
|
int hud_current; //current item in array
|
|
float hud_num_img; // if this gets close to MAX_QC_IMAGES then deny new ones
|
|
float hud_x[MAX_HUD_IMAGES]; // x coordinate for image
|
|
float hud_y[MAX_HUD_IMAGES]; // y coordinate for image
|
|
float hud_mode[MAX_HUD_IMAGES]; // draw mode data, 0 for center screen, 1 for coord
|
|
char *hudimg[MAX_HUD_IMAGES]; // paths to images
|
|
float hud_num_string; // number of strings on screen
|
|
float hud_sx[MAX_HUD_IMAGES]; // x coordinate for string
|
|
float hud_sy[MAX_HUD_IMAGES]; // y coordinate for string
|
|
char *hudstring[MAX_HUD_IMAGES]; // string to be drawn to screen
|
|
|
|
void HUD_Draw (void)
|
|
{
|
|
int i, j;
|
|
qpic_t *p;
|
|
|
|
//initialize i and j
|
|
i = 0;
|
|
j = hud_num_img;
|
|
|
|
//do images first
|
|
while (i < j)
|
|
{
|
|
//set up the pic
|
|
p = Draw_CachePic (hudimg[i]);
|
|
|
|
//draw based on qc_mode
|
|
if (hud_mode[i] == 0) //draw center
|
|
Draw_Pic(((vid.width - p->width)>>1),((vid.height - p->height)>>1), p);
|
|
else //draw coord
|
|
Draw_Pic(hud_x[i],hud_y[i],p);
|
|
|
|
//increment i
|
|
i = i + 1;
|
|
}
|
|
|
|
//reset i and j
|
|
i = 0;
|
|
j = hud_num_string;
|
|
|
|
//now draw text on top of the images
|
|
while (i < j)
|
|
{
|
|
//draw the text at the specified x and y coordinate
|
|
Draw_String (hud_sx[i], hud_sy[i], hudstring[i], 0);
|
|
|
|
//increment i
|
|
i = i + 1;
|
|
}
|
|
}
|
|
|
|
void PF_HUD_CoordPrint (void)
|
|
{
|
|
//make sure we haven't loaded more than MAX_HUD_IMAGES
|
|
if (hud_num_string >= MAX_HUD_IMAGES)
|
|
PR_RunError ("PF_HUD_CoordPrint: Too Many Strings!");
|
|
|
|
//set hud_current equal to the first parameter
|
|
hud_current = G_FLOAT(OFS_PARM0);
|
|
|
|
//set hud_sx and hud_sy equal to parameter 2 and 3
|
|
hud_sx[hud_current] = G_FLOAT(OFS_PARM1);
|
|
hud_sy[hud_current] = G_FLOAT(OFS_PARM2);
|
|
|
|
//set hudstring equal to the fourth parameter
|
|
hudstring[hud_current] = G_STRING(OFS_PARM3);
|
|
|
|
//increment hud_num_string
|
|
hud_num_string = hud_num_string + 1;
|
|
}
|
|
|
|
void PF_HUD_draw_coord (void)
|
|
{
|
|
//make sure we haven't loaded more than MAX_HUD_IMAGES
|
|
if (hud_num_img >= MAX_HUD_IMAGES)
|
|
PR_RunError ("PF_HUD_draw_coord: Too Many Images!");
|
|
|
|
//set hud_current equal to the first parameter
|
|
hud_current = G_FLOAT(OFS_PARM0);
|
|
|
|
//set hud_mode to 1
|
|
hud_mode[hud_current] = 1;
|
|
|
|
//set hud_x and hud_y equal to parameter 2 and 3
|
|
hud_x[hud_current] = G_FLOAT(OFS_PARM1);
|
|
hud_y[hud_current] = G_FLOAT(OFS_PARM2);
|
|
|
|
//set hudimg equal to the fourth parameter
|
|
hudimg[hud_current] = G_STRING(OFS_PARM3);
|
|
|
|
//increment hud_num_img
|
|
hud_num_img = hud_num_img + 1;
|
|
}
|
|
|
|
void PF_HUD_draw_center (void)
|
|
{
|
|
//make sure we haven't loaded more than MAX_HUD_IMAGES
|
|
if (hud_num_img >= MAX_HUD_IMAGES)
|
|
PR_RunError ("PF_HUD_draw_center: Too Many Images!");
|
|
|
|
//set hud_current equal to the first parameter
|
|
hud_current = G_FLOAT(OFS_PARM0);
|
|
|
|
//set hud_mode to 0
|
|
hud_mode[hud_current] = 0;
|
|
|
|
//set hudimg equal to the second parameter
|
|
hudimg[hud_current] = G_STRING(OFS_PARM1);
|
|
|
|
//increment hud_num_img
|
|
hud_num_img = hud_num_img + 1;
|
|
}
|
|
|
|
/*
|
|
========================
|
|
PF_init_hud_draw
|
|
|
|
Turns on HUD Image drawing mode.
|
|
All images stored in array hudimg will appear on screen.
|
|
All text stored in array hudstring will appear on screen.
|
|
========================
|
|
*/
|
|
void PF_init_hud_draw (void)
|
|
{
|
|
//turn on HUD Image drawing mode
|
|
hud_image = 1;
|
|
}
|
|
|
|
/*
|
|
========================
|
|
PF_stop_hud_draw
|
|
|
|
Turns off HUD Image drawing mode.
|
|
========================
|
|
*/
|
|
void PF_stop_hud_draw (void)
|
|
{
|
|
int i, j;
|
|
|
|
//turn off HUD Image drawing mode
|
|
hud_image = 0;
|
|
|
|
//need to reset our variables
|
|
|
|
//initialize i and j
|
|
i = 0;
|
|
j = hud_num_img;
|
|
|
|
//reset images first
|
|
while (i < j)
|
|
{
|
|
//reset hud_mode
|
|
hud_mode[i] = 0;
|
|
|
|
//reset hud_x and hud_y
|
|
hud_x[i] = 0;
|
|
hud_y[i] = 0;
|
|
|
|
//reset hudimg
|
|
hudimg[i] = "";
|
|
|
|
//increment i
|
|
i = i + 1;
|
|
}
|
|
|
|
//reset i and j
|
|
i = 0;
|
|
j = hud_num_string;
|
|
|
|
//now reset strings
|
|
while (i < j)
|
|
{
|
|
//reset hud_sx and hud_sy
|
|
hud_sx[i] = 0;
|
|
hud_sy[i] = 0;
|
|
|
|
//reset hudstring
|
|
hudstring[i] = "";
|
|
|
|
//increment i
|
|
i = i + 1;
|
|
}
|
|
|
|
//reset hud_num_img
|
|
hud_num_img = 0;
|
|
|
|
//reset hud_num_string
|
|
hud_num_string = 0;
|
|
}
|
|
|
|
//end new image precaching / loading code -Xsniper
|
|
|
|
// Xsniper - Added Bot Support
|
|
|
|
/*
|
|
==========================
|
|
PF_get_numbots
|
|
|
|
Called from qc to get number of bots.
|
|
==========================
|
|
*/
|
|
void PF_get_numbots (void)
|
|
{
|
|
G_FLOAT(OFS_RETURN) = numbots;
|
|
}
|
|
|
|
/*
|
|
==========================
|
|
PF_set_numbots
|
|
|
|
Called from qc to set the number of bots.
|
|
==========================
|
|
*/
|
|
void PF_set_numbots (void)
|
|
{
|
|
numbots = G_FLOAT(OFS_PARM0);
|
|
}
|
|
|
|
// Xsniper Added Width and Height Commands
|
|
|
|
/*
|
|
==========================
|
|
PF_get_vid_width
|
|
|
|
Called from qc to get width of the screen.
|
|
==========================
|
|
*/
|
|
void PF_get_vid_width (void)
|
|
{
|
|
G_FLOAT(OFS_RETURN) = vid.width;
|
|
}
|
|
|
|
/*
|
|
==========================
|
|
PF_get_vid_height
|
|
|
|
Called from qc to get height of the screen.
|
|
==========================
|
|
*/
|
|
void PF_get_vid_height (void)
|
|
{
|
|
G_FLOAT(OFS_RETURN) = vid.height;
|
|
}
|
|
|
|
/*
|
|
==========================
|
|
PF_get_engine_version
|
|
|
|
Called from qc to get the current engine version.
|
|
|
|
0: MQ
|
|
1: HQ
|
|
==========================
|
|
*/
|
|
void PF_get_engine_version (void)
|
|
{
|
|
G_FLOAT(OFS_RETURN) = ENGINE_VERSION;
|
|
}
|
|
|
|
//Xsniper - End
|
|
|
|
void PF_precache_file (void)
|
|
{ // precache_file is only used to copy files with qcc, it does nothing
|
|
G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
|
|
}
|
|
|
|
void PF_precache_sound (void)
|
|
{
|
|
char *s;
|
|
int i;
|
|
|
|
if (sv.state != ss_loading)
|
|
PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
|
|
|
|
s = G_STRING(OFS_PARM0);
|
|
G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
|
|
PR_CheckEmptyString (s);
|
|
|
|
for (i=0 ; i<MAX_SOUNDS ; i++)
|
|
{
|
|
if (!sv.sound_precache[i])
|
|
{
|
|
sv.sound_precache[i] = s;
|
|
return;
|
|
}
|
|
if (!strcmp(sv.sound_precache[i], s))
|
|
return;
|
|
}
|
|
PR_RunError ("PF_precache_sound: overflow");
|
|
}
|
|
|
|
void PF_precache_model (void)
|
|
{
|
|
char *s;
|
|
int i;
|
|
|
|
if (sv.state != ss_loading)
|
|
PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
|
|
|
|
s = G_STRING(OFS_PARM0);
|
|
G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
|
|
PR_CheckEmptyString (s);
|
|
|
|
if (gl_particle_fire.value)
|
|
{
|
|
if (!strcmp (s, "progs/flame.mdl"))
|
|
s = "progs/fire.mdl";
|
|
|
|
if (!strcmp (s, "progs/flame2.mdl") ||
|
|
!strcmp (s, "progs/flame3.mdl"))
|
|
s = "progs/fire2.mdl";
|
|
}
|
|
|
|
for (i=0 ; i<MAX_MODELS ; i++)
|
|
{
|
|
if (!sv.model_precache[i])
|
|
{
|
|
sv.model_precache[i] = s;
|
|
sv.models[i] = Mod_ForName (s, true);
|
|
return;
|
|
}
|
|
if (!strcmp(sv.model_precache[i], s))
|
|
return;
|
|
}
|
|
PR_RunError ("PF_precache_model: overflow");
|
|
}
|
|
|
|
|
|
void PF_coredump (void)
|
|
{
|
|
ED_PrintEdicts ();
|
|
}
|
|
|
|
void PF_traceon (void)
|
|
{
|
|
pr_trace = true;
|
|
}
|
|
|
|
void PF_traceoff (void)
|
|
{
|
|
pr_trace = false;
|
|
}
|
|
|
|
void PF_eprint (void)
|
|
{
|
|
ED_PrintNum (G_EDICTNUM(OFS_PARM0));
|
|
}
|
|
|
|
/*
|
|
===============
|
|
PF_walkmove
|
|
|
|
float(float yaw, float dist) walkmove
|
|
===============
|
|
*/
|
|
void PF_walkmove (void)
|
|
{
|
|
edict_t *ent;
|
|
float yaw, dist;
|
|
vec3_t move;
|
|
dfunction_t *oldf;
|
|
int oldself;
|
|
|
|
ent = PROG_TO_EDICT(pr_global_struct->self);
|
|
yaw = G_FLOAT(OFS_PARM0);
|
|
dist = G_FLOAT(OFS_PARM1);
|
|
|
|
if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
|
|
{
|
|
G_FLOAT(OFS_RETURN) = 0;
|
|
return;
|
|
}
|
|
|
|
yaw = yaw*6.283186307179586 / 360; // Tomaz Speed
|
|
|
|
move[0] = cos(yaw)*dist;
|
|
move[1] = sin(yaw)*dist;
|
|
move[2] = 0;
|
|
|
|
// save program state, because SV_movestep may call other progs
|
|
oldf = pr_xfunction;
|
|
oldself = pr_global_struct->self;
|
|
|
|
G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
|
|
|
|
|
|
// restore program state
|
|
pr_xfunction = oldf;
|
|
pr_global_struct->self = oldself;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
PF_droptofloor
|
|
|
|
void() droptofloor
|
|
===============
|
|
*/
|
|
void PF_droptofloor (void)
|
|
{
|
|
edict_t *ent;
|
|
vec3_t end;
|
|
trace_t trace;
|
|
|
|
ent = PROG_TO_EDICT(pr_global_struct->self);
|
|
|
|
VectorCopy (ent->v.origin, end);
|
|
end[2] -= 256;
|
|
|
|
trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
|
|
|
|
if (trace.fraction == 1 || trace.allsolid)
|
|
G_FLOAT(OFS_RETURN) = 0;
|
|
else
|
|
{
|
|
VectorCopy (trace.endpos, ent->v.origin);
|
|
SV_LinkEdict (ent, false);
|
|
ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
|
|
ent->v.groundentity = EDICT_TO_PROG(trace.ent);
|
|
G_FLOAT(OFS_RETURN) = 1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
PF_lightstyle
|
|
|
|
void(float style, string value) lightstyle
|
|
===============
|
|
*/
|
|
void PF_lightstyle (void)
|
|
{
|
|
int style;
|
|
char *val;
|
|
client_t *client;
|
|
int j;
|
|
|
|
style = G_FLOAT(OFS_PARM0);
|
|
val = G_STRING(OFS_PARM1);
|
|
|
|
// change the string in sv
|
|
sv.lightstyles[style] = val;
|
|
|
|
// send message to all clients on this server
|
|
if (sv.state != ss_active)
|
|
return;
|
|
|
|
for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
|
|
if (client->active || client->spawned)
|
|
{
|
|
MSG_WriteChar (&client->message, svc_lightstyle);
|
|
MSG_WriteChar (&client->message,style);
|
|
MSG_WriteString (&client->message, val);
|
|
}
|
|
}
|
|
|
|
void PF_rint (void)
|
|
{
|
|
float f;
|
|
f = G_FLOAT(OFS_PARM0);
|
|
if (f > 0)
|
|
G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
|
|
else
|
|
G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
|
|
}
|
|
void PF_floor (void)
|
|
{
|
|
G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
|
|
}
|
|
void PF_ceil (void)
|
|
{
|
|
G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
|
|
}
|
|
|
|
|
|
/*
|
|
=============
|
|
PF_checkbottom
|
|
=============
|
|
*/
|
|
void PF_checkbottom (void)
|
|
{
|
|
edict_t *ent;
|
|
|
|
ent = G_EDICT(OFS_PARM0);
|
|
|
|
G_FLOAT(OFS_RETURN) = SV_CheckBottom (ent);
|
|
}
|
|
|
|
/*
|
|
=============
|
|
PF_pointcontents
|
|
=============
|
|
*/
|
|
void PF_pointcontents (void)
|
|
{
|
|
float *v;
|
|
|
|
v = G_VECTOR(OFS_PARM0);
|
|
|
|
G_FLOAT(OFS_RETURN) = SV_PointContents (v);
|
|
}
|
|
|
|
/*
|
|
=============
|
|
PF_nextent
|
|
|
|
entity nextent(entity)
|
|
=============
|
|
*/
|
|
void PF_nextent (void)
|
|
{
|
|
int i;
|
|
edict_t *ent;
|
|
|
|
i = G_EDICTNUM(OFS_PARM0);
|
|
while (1)
|
|
{
|
|
i++;
|
|
if (i == sv.num_edicts)
|
|
{
|
|
RETURN_EDICT(sv.edicts);
|
|
return;
|
|
}
|
|
ent = EDICT_NUM(i);
|
|
if (!ent->free)
|
|
{
|
|
RETURN_EDICT(ent);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
=============
|
|
PF_aim
|
|
|
|
Pick a vector for the player to shoot along
|
|
vector aim(entity, missilespeed)
|
|
=============
|
|
*/
|
|
cvar_t sv_aim = {"sv_aim", "1000"};
|
|
void PF_aim (void)
|
|
{
|
|
edict_t *ent, *check, *bestent;
|
|
vec3_t start, dir, end, bestdir;
|
|
int i, j;
|
|
trace_t tr;
|
|
float dist, bestdist;
|
|
float speed;
|
|
|
|
ent = G_EDICT(OFS_PARM0);
|
|
speed = G_FLOAT(OFS_PARM1);
|
|
|
|
VectorCopy (ent->v.origin, start);
|
|
start[2] += 20;
|
|
|
|
// try sending a trace straight
|
|
VectorCopy (pr_global_struct->v_forward, dir);
|
|
VectorMA (start, 2048, dir, end);
|
|
tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
|
|
if (tr.ent && tr.ent->v.takedamage == DAMAGE_AIM
|
|
&& (!teamplay.value || ent->v.team <=0 || ent->v.team != tr.ent->v.team) )
|
|
{
|
|
VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
|
|
return;
|
|
}
|
|
|
|
|
|
// try all possible entities
|
|
VectorCopy (dir, bestdir);
|
|
bestdist = sv_aim.value;
|
|
bestent = NULL;
|
|
|
|
check = NEXT_EDICT(sv.edicts);
|
|
for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
|
|
{
|
|
if (check->v.takedamage != DAMAGE_AIM)
|
|
continue;
|
|
if (check == ent)
|
|
continue;
|
|
if (teamplay.value && ent->v.team > 0 && ent->v.team == check->v.team)
|
|
continue; // don't aim at teammate
|
|
for (j=0 ; j<3 ; j++)
|
|
end[j] = check->v.origin[j]
|
|
+ 0.5*(check->v.mins[j] + check->v.maxs[j]);
|
|
VectorSubtract (end, start, dir);
|
|
VectorNormalize (dir);
|
|
dist = DotProduct (dir, pr_global_struct->v_forward);
|
|
if (dist < bestdist)
|
|
continue; // to far to turn
|
|
tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
|
|
if (tr.ent == check)
|
|
{ // can shoot at this one
|
|
bestdist = dist;
|
|
bestent = check;
|
|
}
|
|
}
|
|
|
|
if (bestent)
|
|
{
|
|
VectorSubtract (bestent->v.origin, ent->v.origin, dir);
|
|
dist = DotProduct (dir, pr_global_struct->v_forward);
|
|
VectorScale (pr_global_struct->v_forward, dist, end);
|
|
end[2] = dir[2];
|
|
VectorNormalize (end);
|
|
VectorCopy (end, G_VECTOR(OFS_RETURN));
|
|
}
|
|
else
|
|
{
|
|
VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
|
|
}
|
|
}
|
|
|
|
/*
|
|
==============
|
|
PF_changeyaw
|
|
|
|
This was a major timewaster in progs, so it was converted to C
|
|
==============
|
|
*/
|
|
void PF_changeyaw (void)
|
|
{
|
|
edict_t *ent;
|
|
float ideal, current, move, speed;
|
|
|
|
ent = PROG_TO_EDICT(pr_global_struct->self);
|
|
current = anglemod( ent->v.angles[1] );
|
|
ideal = ent->v.ideal_yaw;
|
|
speed = ent->v.yaw_speed;
|
|
|
|
if (current == ideal)
|
|
return;
|
|
move = ideal - current;
|
|
if (ideal > current)
|
|
{
|
|
if (move >= 180)
|
|
move = move - 360;
|
|
}
|
|
else
|
|
{
|
|
if (move <= -180)
|
|
move = move + 360;
|
|
}
|
|
if (move > 0)
|
|
{
|
|
if (move > speed)
|
|
move = speed;
|
|
}
|
|
else
|
|
{
|
|
if (move < -speed)
|
|
move = -speed;
|
|
}
|
|
|
|
ent->v.angles[1] = anglemod (current + move);
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
MESSAGE WRITING
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
#define MSG_BROADCAST 0 // unreliable to all
|
|
#define MSG_ONE 1 // reliable to one (msg_entity)
|
|
#define MSG_ALL 2 // reliable to all
|
|
#define MSG_INIT 3 // write to the init string
|
|
|
|
sizebuf_t *WriteDest (void)
|
|
{
|
|
int entnum;
|
|
int dest;
|
|
edict_t *ent;
|
|
|
|
dest = G_FLOAT(OFS_PARM0);
|
|
switch (dest)
|
|
{
|
|
case MSG_BROADCAST:
|
|
return &sv.datagram;
|
|
|
|
case MSG_ONE:
|
|
ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
|
|
entnum = NUM_FOR_EDICT(ent);
|
|
if (entnum < 1 || entnum > svs.maxclients)
|
|
PR_RunError ("WriteDest: not a client");
|
|
return &svs.clients[entnum-1].message;
|
|
|
|
case MSG_ALL:
|
|
return &sv.reliable_datagram;
|
|
|
|
case MSG_INIT:
|
|
return &sv.signon;
|
|
|
|
default:
|
|
PR_RunError ("WriteDest: bad destination");
|
|
break;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void PF_WriteByte (void)
|
|
{
|
|
MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
|
|
}
|
|
|
|
void PF_WriteChar (void)
|
|
{
|
|
MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
|
|
}
|
|
|
|
void PF_WriteShort (void)
|
|
{
|
|
MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
|
|
}
|
|
|
|
void PF_WriteLong (void)
|
|
{
|
|
MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
|
|
}
|
|
|
|
void PF_WriteAngle (void)
|
|
{
|
|
MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
|
|
}
|
|
|
|
void PF_WriteCoord (void)
|
|
{
|
|
MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1));
|
|
}
|
|
|
|
void PF_WriteString (void)
|
|
{
|
|
MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
|
|
}
|
|
|
|
|
|
void PF_WriteEntity (void)
|
|
{
|
|
MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
int SV_ModelIndex (char *name);
|
|
|
|
void PF_makestatic (void)
|
|
{
|
|
edict_t *ent;
|
|
int i;
|
|
|
|
ent = G_EDICT(OFS_PARM0);
|
|
|
|
MSG_WriteByte (&sv.signon,svc_spawnstatic);
|
|
|
|
MSG_WriteByte (&sv.signon, SV_ModelIndex(pr_strings + ent->v.model));
|
|
|
|
MSG_WriteByte (&sv.signon, ent->v.frame);
|
|
MSG_WriteByte (&sv.signon, ent->v.colormap);
|
|
MSG_WriteByte (&sv.signon, ent->v.skin);
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
MSG_WriteCoord(&sv.signon, ent->v.origin[i]);
|
|
MSG_WriteAngle(&sv.signon, ent->v.angles[i]);
|
|
}
|
|
|
|
// throw the entity away now
|
|
ED_Free (ent);
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
/*
|
|
==============
|
|
PF_setspawnparms
|
|
==============
|
|
*/
|
|
void PF_setspawnparms (void)
|
|
{
|
|
edict_t *ent;
|
|
int i;
|
|
client_t *client;
|
|
|
|
ent = G_EDICT(OFS_PARM0);
|
|
i = NUM_FOR_EDICT(ent);
|
|
if (i < 1 || i > svs.maxclients)
|
|
PR_RunError ("Entity is not a client");
|
|
|
|
// copy spawn parms out of the client_t
|
|
client = svs.clients + (i-1);
|
|
|
|
for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
|
|
(&pr_global_struct->parm1)[i] = client->spawn_parms[i];
|
|
}
|
|
|
|
/*
|
|
==============
|
|
PF_changelevel
|
|
==============
|
|
*/
|
|
void PF_changelevel (void)
|
|
{
|
|
char *s;
|
|
|
|
// make sure we don't issue two changelevels
|
|
if (svs.changelevel_issued)
|
|
return;
|
|
svs.changelevel_issued = true;
|
|
|
|
s = G_STRING(OFS_PARM0);
|
|
Cbuf_AddText (va("changelevel %s\n",s));
|
|
}
|
|
|
|
void PF_Fixme (void)
|
|
{
|
|
PR_RunError ("unimplemented bulitin");
|
|
}
|
|
|
|
// Tomaz - QuakeC String Manipulation Begin
|
|
void PF_zone (void)
|
|
{
|
|
char *m, *p;
|
|
m = G_STRING(OFS_PARM0);
|
|
p = Z_Malloc(Q_strlen(m) + 1);
|
|
Q_strcpy(p, m);
|
|
|
|
G_INT(OFS_RETURN) = p - pr_strings;
|
|
}
|
|
|
|
|
|
void PF_unzone (void)
|
|
{
|
|
|
|
Z_Free(G_STRING(OFS_PARM0));
|
|
G_INT(OFS_PARM0) = OFS_NULL; // empty the def
|
|
};
|
|
|
|
void PF_strlen (void)
|
|
{
|
|
|
|
char *p = G_STRING(OFS_PARM0);
|
|
G_FLOAT(OFS_RETURN) = strlen(p);
|
|
}
|
|
|
|
char pr_strcat_buf [128]; // need this becuase pr_string_temp sucks
|
|
|
|
void PF_strcat (void)
|
|
{
|
|
char *s1, *s2;
|
|
|
|
memset(pr_strcat_buf, 0, 127);
|
|
s1 = G_STRING(OFS_PARM0);
|
|
s2 = PF_VarString(1);
|
|
strcpy(pr_strcat_buf, s1);
|
|
strcat(pr_strcat_buf, s2);
|
|
G_INT(OFS_RETURN) = pr_strcat_buf - pr_strings;
|
|
}
|
|
|
|
void PF_substring (void)
|
|
{
|
|
|
|
int ltwo, start;
|
|
char *p, *d;
|
|
d = pr_string_temp;
|
|
|
|
p = G_STRING(OFS_PARM0);
|
|
start = (int)G_FLOAT(OFS_PARM1); // for some reason, Quake doesn't like G_INT
|
|
ltwo = (int)G_FLOAT(OFS_PARM2);
|
|
if ((unsigned)start > strlen(p))
|
|
start = strlen(p) - 1;
|
|
|
|
// cap values
|
|
if (start < 0)
|
|
start = 0;
|
|
if (ltwo < 0)
|
|
ltwo = 0;
|
|
|
|
p += start;
|
|
Q_strncpy(d, p, ltwo);
|
|
G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
|
|
|
|
}
|
|
|
|
// thanks zoid
|
|
void PF_stof (void)
|
|
{
|
|
char *s;
|
|
|
|
s = G_STRING(OFS_PARM0);
|
|
G_FLOAT(OFS_RETURN) = atof(s);
|
|
}
|
|
|
|
void PF_stov (void)
|
|
{
|
|
char *v;
|
|
int i;
|
|
vec3_t d;
|
|
|
|
v = G_STRING(OFS_PARM0);
|
|
|
|
for (i=0; i<3; i++)
|
|
{
|
|
while(v && (v[0] == ' ' || v[0] == '\'')) //skip unneeded data
|
|
v++;
|
|
d[i] = atof(v);
|
|
while (v && v[0] != ' ') // skip to next space
|
|
v++;
|
|
}
|
|
VectorCopy (d, G_VECTOR(OFS_RETURN));
|
|
}
|
|
// Tomaz - QuakeC String Manipulation End
|
|
|
|
// Tomaz - QuakeC File System Begin
|
|
void PF_open (void)
|
|
{
|
|
char *p = G_STRING(OFS_PARM0);
|
|
char *ftemp;
|
|
int fmode = G_FLOAT(OFS_PARM1);
|
|
int h = 0, fsize = 0;
|
|
|
|
switch (fmode)
|
|
{
|
|
case 0: // read
|
|
Sys_FileOpenRead (va("%s/%s",com_gamedir, p), &h);
|
|
G_FLOAT(OFS_RETURN) = (float) h;
|
|
return;
|
|
case 1: // append -- this is nasty
|
|
// copy whole file into the zone
|
|
fsize = Sys_FileOpenRead(va("%s/%s",com_gamedir, p), &h);
|
|
if (h == -1)
|
|
{
|
|
h = Sys_FileOpenWrite(va("%s/%s",com_gamedir, p));
|
|
G_FLOAT(OFS_RETURN) = (float) h;
|
|
return;
|
|
}
|
|
ftemp = Z_Malloc(fsize + 1);
|
|
Sys_FileRead(h, ftemp, fsize);
|
|
Sys_FileClose(h);
|
|
// spit it back out
|
|
h = Sys_FileOpenWrite(va("%s/%s",com_gamedir, p));
|
|
Sys_FileWrite(h, ftemp, fsize);
|
|
Z_Free(ftemp); // free it from memory
|
|
G_FLOAT(OFS_RETURN) = (float) h; // return still open handle
|
|
return;
|
|
default: // write
|
|
h = Sys_FileOpenWrite (va("%s/%s", com_gamedir, p));
|
|
G_FLOAT(OFS_RETURN) = (float) h;
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
void PF_close (void)
|
|
{
|
|
int h = (int)G_FLOAT(OFS_PARM0);
|
|
Sys_FileClose(h);
|
|
}
|
|
|
|
void PF_read (void)
|
|
{
|
|
// reads one line (to a \n) into a string
|
|
int h = (int)G_FLOAT(OFS_PARM0);
|
|
int test;
|
|
char *p;
|
|
|
|
memset(pr_string_temp, 0, 127);
|
|
p = pr_string_temp;
|
|
Sys_FileRead(h, p, 1);
|
|
while (p && p[0] != '\n')
|
|
{
|
|
*p++;
|
|
test = Sys_FileRead(h, p, 1);
|
|
if (p[0] == 13) // carriage return
|
|
Sys_FileRead(h, p, 1); // skip
|
|
if (!test)
|
|
break;
|
|
};
|
|
p[0] = 0;
|
|
if (strlen(pr_string_temp) == 0)
|
|
G_INT(OFS_RETURN) = OFS_NULL;
|
|
else
|
|
G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
|
|
}
|
|
|
|
void PF_write (void)
|
|
{
|
|
// writes to file, like bprint
|
|
float handle = G_FLOAT(OFS_PARM0);
|
|
char *str = PF_VarString(1);
|
|
Sys_FileWrite (handle, str, strlen(str));
|
|
|
|
}
|
|
// Tomaz - QuakeC File System End
|
|
|
|
|
|
builtin_t pr_builtin[] =
|
|
{
|
|
PF_Fixme,
|
|
PF_makevectors, // #1 void(entity e) makevectors
|
|
PF_setorigin, // #2 void(entity e, vector o) setorigin
|
|
PF_setmodel, // #3 void(entity e, string m) setmodel
|
|
PF_setsize, // #4 void(entity e, vector min, vector max) setsize
|
|
PF_Fixme, // #5
|
|
PF_break, // #6 void() break
|
|
PF_random, // #7 float() random
|
|
PF_sound, // #8 void(entity e, float chan, string samp) sound
|
|
PF_normalize, // #9 vector(vector v) normalize
|
|
|
|
PF_error, // #10 void(string e) error
|
|
PF_objerror, // #11 void(string e) objerror
|
|
PF_vlen, // #12 float(vector v) vlen
|
|
PF_vectoyaw, // #13 float(vector v) vectoyaw
|
|
PF_Spawn, // #14 entity() spawn
|
|
PF_Remove, // #15 void(entity e) remove
|
|
PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
|
|
PF_checkclient, // #17 entity() clientlist
|
|
PF_Find, // #18 entity(entity start, .string fld, string match) find
|
|
PF_precache_sound, // #19 void(string s) precache_sound
|
|
|
|
PF_precache_model, // #20 void(string s) precache_model
|
|
PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
|
|
PF_findradius, // #22 entity(vector org, float rad) findradius
|
|
PF_bprint, // #23 void(string s) bprint
|
|
PF_sprint, // #24 void(entity client, string s) sprint
|
|
PF_dprint, // #25 void(string s) dprint
|
|
PF_ftos, // #26 void(string s) ftos
|
|
PF_vtos, // #27 void(string s) vtos
|
|
PF_coredump, // #28
|
|
PF_traceon, // #29
|
|
|
|
PF_traceoff, // #30
|
|
PF_eprint, // #31 void(entity e) debug print an entire entity
|
|
PF_walkmove, // #32 float(float yaw, float dist) walkmove
|
|
PF_Fixme, // #33 float(float yaw, float dist) walkmove
|
|
PF_droptofloor, // #34
|
|
PF_lightstyle, // #35
|
|
PF_rint, // #36
|
|
PF_floor, // #37
|
|
PF_ceil, // #38
|
|
PF_Fixme, // #39
|
|
|
|
PF_checkbottom, // #40
|
|
PF_pointcontents, // #41
|
|
PF_Fixme, // #42
|
|
PF_fabs, // #43
|
|
PF_aim, // #44
|
|
PF_cvar, // #45
|
|
PF_localcmd, // #46
|
|
PF_nextent, // #47
|
|
PF_particle, // #48
|
|
PF_changeyaw, // #49
|
|
|
|
PF_Fixme, // #50
|
|
PF_vectoangles, // #51
|
|
PF_WriteByte, // #52
|
|
PF_WriteChar, // #53
|
|
PF_WriteShort, // #54
|
|
PF_WriteLong, // #55
|
|
PF_WriteCoord, // #56
|
|
PF_WriteAngle, // #57
|
|
PF_WriteString, // #58
|
|
PF_WriteEntity, // #59
|
|
|
|
PF_Fixme, // #60
|
|
PF_Fixme, // #61
|
|
PF_Fixme, // #62
|
|
PF_Fixme, // #63
|
|
PF_Fixme, // #64
|
|
PF_Fixme, // #65
|
|
PF_Fixme, // #66
|
|
SV_MoveToGoal, // #67
|
|
PF_precache_file, // #68
|
|
PF_makestatic, // #69
|
|
|
|
PF_changelevel, // #70
|
|
PF_Fixme, // #71
|
|
PF_cvar_set, // #72
|
|
PF_centerprint, // #73
|
|
PF_ambientsound, // #74
|
|
PF_precache_model, // #75
|
|
PF_precache_sound, // #76
|
|
PF_precache_file, // #77
|
|
PF_setspawnparms, // #78
|
|
|
|
// Tomaz - QuakeC String Manipulation Begin
|
|
PF_zone, // #79
|
|
|
|
PF_unzone, // #80
|
|
PF_strlen, // #81
|
|
PF_strcat, // #82
|
|
PF_substring, // #83
|
|
PF_stof, // #84
|
|
PF_stov, // #85
|
|
// Tomaz - QuakeC String Manipulation End
|
|
|
|
// Tomaz - QuakeC File System Begin
|
|
PF_open, // #86
|
|
PF_close, // #87
|
|
PF_read, // #88
|
|
PF_write, // #89
|
|
// Tomaz - QuakeC File System End
|
|
|
|
PF_Fixme, // #90
|
|
PF_Fixme, // #91
|
|
PF_Fixme, // #92
|
|
PF_Fixme, // #93
|
|
PF_Fixme, // #94
|
|
PF_Fixme, // #95
|
|
PF_Fixme, // #96
|
|
PF_Fixme, // #97
|
|
PF_Fixme, // #98
|
|
PF_Fixme, // #99
|
|
PF_Fixme, // #100
|
|
PF_Fixme, // #101
|
|
PF_Fixme, // #102
|
|
PF_Fixme, // #103
|
|
PF_Fixme, // #104
|
|
PF_Fixme, // #105
|
|
PF_Fixme, // #106
|
|
PF_Fixme, // #107
|
|
PF_Fixme, // #108
|
|
PF_Fixme, // #109
|
|
PF_Fixme, // #110
|
|
PF_Fixme, // #111
|
|
PF_Fixme, // #112
|
|
PF_Fixme, // #113
|
|
PF_Fixme, // #114
|
|
PF_Fixme, // #115
|
|
PF_Fixme, // #116
|
|
PF_Fixme, // #117
|
|
PF_Fixme, // #118
|
|
PF_Fixme, // #119
|
|
PF_Fixme, // #120
|
|
PF_Fixme, // #121
|
|
PF_Fixme, // #122
|
|
PF_Fixme, // #123
|
|
PF_Fixme, // #124
|
|
PF_Fixme, // #125
|
|
PF_Fixme, // #126
|
|
PF_Fixme, // #127
|
|
PF_Fixme, // #128
|
|
PF_Fixme, // #129
|
|
PF_Fixme, // #130
|
|
PF_Fixme, // #131
|
|
PF_Fixme, // #132
|
|
PF_Fixme, // #133
|
|
PF_Fixme, // #134
|
|
PF_Fixme, // #135
|
|
PF_Fixme, // #136
|
|
PF_Fixme, // #137
|
|
PF_Fixme, // #138
|
|
PF_Fixme, // #139
|
|
PF_Fixme, // #140
|
|
PF_Fixme, // #141
|
|
PF_Fixme, // #142
|
|
PF_Fixme, // #143
|
|
PF_Fixme, // #144
|
|
PF_Fixme, // #145
|
|
PF_Fixme, // #146
|
|
PF_Fixme, // #147
|
|
PF_Fixme, // #148
|
|
PF_Fixme, // #149
|
|
PF_Fixme, // #150
|
|
PF_Fixme, // #151
|
|
PF_Fixme, // #152
|
|
PF_Fixme, // #153
|
|
PF_Fixme, // #154
|
|
PF_Fixme, // #155
|
|
PF_Fixme, // #156
|
|
PF_Fixme, // #157
|
|
PF_Fixme, // #158
|
|
PF_Fixme, // #159
|
|
PF_Fixme, // #160
|
|
PF_Fixme, // #161
|
|
PF_Fixme, // #162
|
|
PF_Fixme, // #163
|
|
PF_Fixme, // #164
|
|
PF_Fixme, // #165
|
|
PF_Fixme, // #166
|
|
PF_Fixme, // #167
|
|
PF_Fixme, // #168
|
|
PF_Fixme, // #169
|
|
PF_Fixme, // #170
|
|
PF_Fixme, // #171
|
|
PF_Fixme, // #172
|
|
PF_Fixme, // #173
|
|
PF_Fixme, // #174
|
|
PF_Fixme, // #175
|
|
PF_Fixme, // #176
|
|
PF_Fixme, // #177
|
|
PF_Fixme, // #178
|
|
|
|
//begin new image precaching / loading code -Xsniper
|
|
PF_init_draw, // #179
|
|
PF_stop_draw, // #180
|
|
PF_draw_coord, // #181
|
|
PF_draw_center, // #182
|
|
PF_CoordPrint, // #183
|
|
//end new image precaching / loading code -Xsniper
|
|
|
|
PF_Fixme, // #184
|
|
|
|
// Xsniper - Added Bot Support
|
|
PF_get_numbots, // #185
|
|
PF_set_numbots, // #186
|
|
// Xsniper - End
|
|
|
|
// Xsniper - Added New HUD Draw System
|
|
PF_init_hud_draw, //#187
|
|
PF_stop_hud_draw, //#188
|
|
PF_HUD_draw_coord, //#189
|
|
PF_HUD_draw_center, //#190
|
|
PF_HUD_CoordPrint, //#191
|
|
PF_get_vid_width, //#192
|
|
PF_get_vid_height, //#193
|
|
// Xsniper - End
|
|
|
|
// Xsniper - Added Engine Version Checking
|
|
PF_get_engine_version, //#194
|
|
// Xsniper - End
|
|
|
|
PF_checkextension, // #195
|
|
};
|
|
|
|
builtin_t *pr_builtins = pr_builtin;
|
|
int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
|
|
|