Added support for simple csqc.

This is a subset of csqc, with alternative entry points that can be invoked by compat wrappers.

Also added sv_gameplayfix_setmodelrealbox cvar. Default value of 1 matches QuakeSpasm, whereas a value of 0 matches vanilla quake's behaviour.
This commit is contained in:
Spike 2018-05-01 01:35:14 +01:00 committed by Shpoike
parent 08122cb283
commit fe4b224c7d
42 changed files with 3937 additions and 1165 deletions

View file

@ -100,6 +100,8 @@ void CL_ClearState (void)
CL_ClearTrailStates();
PR_ClearProgs(&cl.qcvm);
// wipe the entire cl structure
memset (&cl, 0, sizeof(cl));
@ -116,6 +118,9 @@ void CL_ClearState (void)
cl.entities = (entity_t *) Hunk_AllocName (cl.max_edicts*sizeof(entity_t), "cl_entities");
//johnfitz
//Spike -- this stuff needs to get reset to defaults.
cl.csqc_sensitivity = 1;
cl.viewent.netstate = nullentitystate;
#ifdef PSET_SCRIPT
PScript_Shutdown();

View file

@ -205,24 +205,6 @@ entity_t *CL_EntityNum (int num)
return &cl.entities[num];
}
static int MSG_ReadEntity(void)
{
int e = (unsigned short)MSG_ReadShort();
if (cl.protocol_pext2 & PEXT2_REPLACEMENTDELTAS)
{
if (e & 0x8000)
{
e = (e & 0x7fff) << 8;
e |= MSG_ReadByte();
}
}
return e;
}
static unsigned int CLFTE_ReadDelta(unsigned int entnum, entity_state_t *news, const entity_state_t *olds, const entity_state_t *baseline)
{
unsigned int predbits = 0;
@ -478,7 +460,7 @@ static unsigned int CLFTE_ReadDelta(unsigned int entnum, entity_state_t *news, c
}
if (bits & UF_TAGINFO)
{
news->tagentity = MSG_ReadEntity();
news->tagentity = MSG_ReadEntity(cl.protocol_pext2);
news->tagindex = MSG_ReadByte();
}
if (bits & UF_LIGHT)
@ -751,6 +733,68 @@ static void CLFTE_ParseEntitiesUpdate(void)
}
}
//csqc entities protocol, payload is identical in both fte+dp. just the svcs differ.
void CLFTE_ParseCSQCEntitiesUpdate(void)
{
/*if (cl.qcvm.extfuncs.CSQC_Ent_Update)
{
edict_t *ed;
for(;;)
{
//replacement deltas now also includes 22bit entity num indicies.
if (cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
{
entnum = (unsigned short)MSG_ReadShort();
removeflag = !!(entnum & 0x8000);
if (entnum & 0x4000)
entnum = (entnum & 0x3fff) | (MSG_ReadByte()<<14);
else
entnum &= ~0x8000;
}
else
{ //otherwise just a 16bit value, with the high bit used as a 'remove' flag
entnum = (unsigned short)MSG_ReadShort();
removeflag = !!(entnum & 0x8000);
entnum &= ~0x8000;
}
if ((!entnum && !removeflag) || msg_badread)
break; //end of svc
if (removeflag)
{
ed = cl.ssqc_to_csqc[entnum];
if (ed)
{
pr_global_struct->self = EDICT_TO_PROG(ed);
if (cl.qcvm.extfuncs.CSQC_Ent_Remove)
PR_ExecuteProgram(cl.qcvm.extfuncs.CSQC_Ent_Remove);
else
ED_Free(ed);
}
}
else
{
// if (cl.csqcdebug)
// packetsize = MSG_ReadShort();
ed = cl.ssqc_to_csqc[entnum];
if (!ed)
{
cl.ssqc_to_csqc[entnum] = ed = ED_Alloc();
ed->v.entnum = entnum;
G_FLOAT(OFS_PARM0) = true;
}
else
G_FLOAT(OFS_PARM0) = false;
pr_global_struct->self = EDICT_TO_PROG(ed);
PR_ExecuteProgram(cl.qcvm.extfuncs.CSQC_Ent_Update);
}
}
}
else*/
Host_Error ("Received svcdp_csqcentities but unable to parse");
}
//darkplaces protocols 5 to 7 use these
#define E5_FULLUPDATE (1<<0)
@ -898,7 +942,7 @@ static void CLDP_ReadDelta(unsigned int entnum, entity_state_t *s, const entity_
s->colormap = MSG_ReadByte();
if (bits & E5_ATTACHMENT)
{
s->tagentity = MSG_ReadEntity();
s->tagentity = MSG_ReadEntity(cl.protocol_pext2);
s->tagindex = MSG_ReadByte();
}
if (bits & E5_LIGHT)
@ -2259,6 +2303,8 @@ void CL_ParseServerMessage (void)
if (cl.protocol == PROTOCOL_VERSION_DP7)
CL_EntitiesDeltaed();
if (*cl.stuffcmdbuf && net_message.cursize < 512)
CL_ParseStuffText("\n"); //there's a few mods that forget to write \ns, that then fuck up other things too. So make sure it gets flushed to the cbuf. the cursize check is to reduce backbuffer overflows that would give a false positive.
return; // end of message
}
@ -2454,10 +2500,12 @@ void CL_ParseServerMessage (void)
case svc_killedmonster:
cl.stats[STAT_MONSTERS]++;
cl.statsf[STAT_MONSTERS] = cl.stats[STAT_MONSTERS];
break;
case svc_foundsecret:
cl.stats[STAT_SECRETS]++;
cl.statsf[STAT_SECRETS] = cl.stats[STAT_SECRETS];
break;
case svc_updatestat:
@ -2562,28 +2610,28 @@ void CL_ParseServerMessage (void)
case svcdp_effect:
case svcdp_effect2:
case svcdp_effect2: //these are kinda pointless when the particle system can do it
if (cl.protocol != PROTOCOL_VERSION_DP7)
Host_Error ("Received svcdp_effect[1|2] but extension not active");
CL_ParseEffect(cmd==svcdp_effect2);
break;
case svcdp_csqcentities:
if (cl.protocol != PROTOCOL_VERSION_DP7)
case svcdp_csqcentities: //FTE uses DP's svc number for nq, because compat (despite fte's svc being first). same payload either way.
if (!(cl.protocol_pext2 & PEXT2_REPLACEMENTDELTAS) && cl.protocol != PROTOCOL_VERSION_DP7)
Host_Error ("Received svcdp_csqcentities but extension not active");
Host_Error ("csqc is not supported");
CLFTE_ParseCSQCEntitiesUpdate();
break;
case svcdp_spawnbaseline2:
case svcdp_spawnbaseline2: //limited to a handful of extra properties.
if (cl.protocol != PROTOCOL_VERSION_DP7)
Host_Error ("Received svcdp_spawnbaseline2 but extension not active");
i = MSG_ReadShort ();
CL_ParseBaseline (CL_EntityNum(i), 7);
break;
case svcdp_spawnstaticsound2:
case svcdp_spawnstaticsound2: //many different ways to use 16bit sounds... no other advantage
if (cl.protocol != PROTOCOL_VERSION_DP7)
Host_Error ("Received svcdp_spawnstaticsound2 but extension not active");
CL_ParseStaticSound (2);
break;
case svcdp_spawnstatic2:
case svcdp_spawnstatic2: //16bit model and frame. no alpha or anything fun.
if (cl.protocol != PROTOCOL_VERSION_DP7)
Host_Error ("Received svcdp_spawnstatic2 but extension not active");
CL_ParseStatic (7);
@ -2633,7 +2681,7 @@ void CL_ParseServerMessage (void)
case svcfte_spawnbaseline2:
if (!(cl.protocol_pext2 & PEXT2_REPLACEMENTDELTAS))
Host_Error ("Received svcfte_spawnbaseline2 but extension not active");
i = MSG_ReadEntity ();
i = MSG_ReadEntity (cl.protocol_pext2);
// must use CL_EntityNum() to force cl.num_entities up
CL_ParseBaseline (CL_EntityNum(i), 6);
break;
@ -2644,6 +2692,17 @@ void CL_ParseServerMessage (void)
CLFTE_ParseEntitiesUpdate();
break;
case svcfte_cgamepacket:
if (cl.qcvm.extfuncs.CSQC_Parse_Event)
{
PR_SwitchQCVM(&cl.qcvm);
PR_ExecuteProgram(cl.qcvm.extfuncs.CSQC_Parse_Event);
PR_SwitchQCVM(NULL);
}
else
Host_Error ("CSQC_Parse_Event: Missing or incompatible CSQC\n");
break;
//voicechat, because we can. why reduce packet sizes if you're not going to use that extra space?!?
case svcfte_voicechat:
if (!(cl.protocol_pext2 & PEXT2_VOICECHAT))

View file

@ -254,6 +254,11 @@ typedef struct
const char *name;
int index;
} particle_precache[MAX_PARTICLETYPES];
struct
{
const char *name;
int index;
} local_particle_precache[MAX_PARTICLETYPES];
#endif
int ackframes[8]; //big enough to cover burst
unsigned int ackframes_count;
@ -281,6 +286,10 @@ typedef struct
int sound_download;
char sound_name[MAX_SOUNDS][MAX_QPATH];
//spike -- end downloads
qcvm_t qcvm; //for csqc.
qboolean csqc_cursorforced; //we want a mouse cursor.
float csqc_sensitivity; //scaler for sensitivity
} client_state_t;

View file

@ -596,7 +596,7 @@ void Cmd_Init (void)
Cmd_AddCommand ("apropos", Cmd_Apropos_f);
Cmd_AddCommand ("find", Cmd_Apropos_f);
Cvar_RegisterVariable (&cl_nopext);
Cvar_RegisterVariable (&cl_nopext);
Cvar_RegisterVariable (&cmd_warncmd);
}
@ -696,7 +696,7 @@ void Cmd_AddCommand2 (const char *cmd_name, xcommand_t function, cmd_source_t sr
cmd_function_t *cmd;
cmd_function_t *cursor,*prev; //johnfitz -- sorted list insert
if (host_initialized) // because hunk allocation would get stomped
if (host_initialized && function) // because hunk allocation would get stomped
Sys_Error ("Cmd_AddCommand after host_initialized");
// fail if the command is a variable name
@ -711,12 +711,16 @@ void Cmd_AddCommand2 (const char *cmd_name, xcommand_t function, cmd_source_t sr
{
if (!Q_strcmp (cmd_name, cmd->name) && cmd->srctype == srctype)
{
Con_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name);
if (cmd->function != function && function)
Con_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name);
return;
}
}
cmd = (cmd_function_t *) Hunk_Alloc (sizeof(cmd_function_t));
if (host_initialized)
cmd = malloc(sizeof(cmd_function_t));
else
cmd = (cmd_function_t *) Hunk_Alloc (sizeof(cmd_function_t));
cmd->name = cmd_name;
cmd->function = function;
cmd->srctype = srctype;
@ -816,8 +820,25 @@ qboolean Cmd_ExecuteString (const char *text, cmd_source_t src)
continue; //src_command can execute anything but server commands (which it ignores, allowing for alternative behaviour)
else if (src == src_server && cmd->srctype != src_server)
continue; //src_server may only execute server commands (such commands must be safe to parse within the context of a network message, so no disconnect/connect/playdemo/etc)
else
else if (cmd->function)
cmd->function ();
else
{
if (cl.qcvm.extfuncs.CSQC_ConsoleCommand)
{
qboolean ret;
PR_SwitchQCVM(&cl.qcvm);
G_INT(OFS_PARM0) = PR_MakeTempString(text);
PR_ExecuteProgram(cl.qcvm.extfuncs.CSQC_ConsoleCommand);
ret = G_FLOAT(OFS_RETURN);
if (!ret)
Con_Printf ("gamecode cannot \"%s\"\n", Cmd_Argv(0));
PR_SwitchQCVM(NULL);
return ret;
}
else
Con_Printf ("gamecode not running, cannot \"%s\"\n", Cmd_Argv(0));
}
return true;
}
}

View file

@ -27,7 +27,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <errno.h>
#ifndef _WIN32
#include <dirent.h>
#include <dirent.h>
#include <fnmatch.h>
#ifndef FNM_CASEFOLD
#define FNM_CASEFOLD 0 //not available. I guess we're not on gnu/linux
#endif
#endif
static char *largv[MAX_NUM_ARGVS + 1];
@ -928,6 +932,20 @@ float MSG_ReadAngle16 (unsigned int flags)
}
//johnfitz
int MSG_ReadEntity(unsigned int pext2)
{
int e = (unsigned short)MSG_ReadShort();
if (pext2 & PEXT2_REPLACEMENTDELTAS)
{
if (e & 0x8000)
{
e = (e & 0x7fff) << 8;
e |= MSG_ReadByte();
}
}
return e;
}
//spike -- for downloads
byte *MSG_ReadData (unsigned int length)
{
@ -1708,6 +1726,7 @@ static int COM_FindFile (const char *filename, int *handle, FILE **file,
char netpath[MAX_OSPATH];
pack_t *pak;
int i, findtime;
const char *ext;
if (file && handle)
Sys_Error ("COM_FindFile: both handle and file set");
@ -1809,10 +1828,14 @@ static int COM_FindFile (const char *filename, int *handle, FILE **file,
}
}
if (strcmp(COM_FileGetExtension(filename), "pcx") != 0
&& strcmp(COM_FileGetExtension(filename), "tga") != 0
&& strcmp(COM_FileGetExtension(filename), "lit") != 0
&& strcmp(COM_FileGetExtension(filename), "ent") != 0)
ext = COM_FileGetExtension(filename);
if (strcmp(ext, "pcx") != 0
&& strcmp(ext, "tga") != 0
&& strcmp(ext, "png") != 0
&& strcmp(ext, "jpg") != 0
&& strcmp(ext, "jpeg") != 0
&& strcmp(ext, "lit") != 0
&& strcmp(ext, "ent") != 0)
Con_DPrintf ("FindFile: can't find %s\n", filename);
else Con_DPrintf2("FindFile: can't find %s\n", filename);
// Log pcx, tga, lit, ent misses only if (developer.value >= 2)
@ -2138,8 +2161,17 @@ static pack_t *COM_LoadPackFile (const char *packfile)
return pack;
}
#ifdef _WIN32
static time_t Sys_FileTimeToTime(FILETIME ft)
{
ULARGE_INTEGER ull;
ull.LowPart = ft.dwLowDateTime;
ull.HighPart = ft.dwHighDateTime;
return ull.QuadPart / 10000000u - 11644473600u;
}
#endif
static void COM_ListSystemFiles(void *ctx, const char *gamedir, const char *ext, qboolean (*cb)(void *ctx, const char *fname))
void COM_ListSystemFiles(void *ctx, const char *gamedir, const char *ext, qboolean (*cb)(void *ctx, const char *fname))
{
#ifdef _WIN32
WIN32_FIND_DATA fdat;
@ -2170,6 +2202,61 @@ static void COM_ListSystemFiles(void *ctx, const char *gamedir, const char *ext,
#endif
}
void COM_ListFiles(void *ctx, const char *gamedir, const char *pattern, qboolean (*cb)(void *ctx, const char *fname, time_t mtime, size_t fsize))
{
char prefixdir[MAX_OSPATH];
char *sl;
sl = strrchr(pattern, '/');
if (sl)
{
sl++;
if (sl-pattern >= MAX_OSPATH)
return;
memcpy(prefixdir, pattern, sl-pattern);
prefixdir[sl-pattern] = 0;
pattern = sl;
}
else
*prefixdir = 0;
#ifdef _WIN32
{
char filestring[MAX_OSPATH];
WIN32_FIND_DATA fdat;
HANDLE fhnd;
q_snprintf (filestring, sizeof(filestring), "%s/%s%s", gamedir, prefixdir, pattern);
fhnd = FindFirstFile(filestring, &fdat);
if (fhnd == INVALID_HANDLE_VALUE)
return;
do
{
q_snprintf (filestring, sizeof(filestring), "%s%s", prefixdir, fdat.cFileName);
cb (ctx, filestring, Sys_FileTimeToTime(fdat.ftLastWriteTime), fdat.nFileSizeLow);
} while (FindNextFile(fhnd, &fdat));
FindClose(fhnd);
}
#else
{
char filestring[MAX_OSPATH];
DIR *dir_p;
struct dirent *dir_t;
q_snprintf (filestring, sizeof(filestring), "%s/%s%s", gamedir, prefixdir, pattern);
dir_p = opendir(filestring);
if (dir_p == NULL)
return;
while ((dir_t = readdir(dir_p)) != NULL)
{
if (!fnmatch(pattern, dir_t->d_name, FNM_NOESCAPE|FNM_PATHNAME|FNM_CASEFOLD))
{
q_snprintf (filestring, sizeof(filestring), "%s%s", prefixdir, dir_t->d_name);
cb (ctx, filestring, 0, 0);
}
}
closedir(dir_p);
}
#endif
}
static qboolean COM_AddPackage(searchpath_t *basepath, const char *pakfile)
{

View file

@ -121,6 +121,7 @@ float MSG_ReadCoord (unsigned int flags);
float MSG_ReadAngle (unsigned int flags);
float MSG_ReadAngle16 (unsigned int flags); //johnfitz
byte *MSG_ReadData (unsigned int length); // spike
int MSG_ReadEntity(unsigned int pext2); //spike
void COM_Effectinfo_Enumerate(int (*cb)(const char *pname)); //spike -- for dp compat

View file

@ -117,23 +117,17 @@ void Con_ToggleConsole_f (void)
history_line = edit_line; //johnfitz -- it should also return you to the bottom of the command history
if (cls.state == ca_connected)
{
IN_Activate();
key_dest = key_game;
}
else
{
M_Menu_Main_f ();
}
}
else
{
IN_Deactivate(modestate == MS_WINDOWED);
key_dest = key_console;
}
SCR_EndLoadingPlaque ();
memset (con_times, 0, sizeof(con_times));
IN_UpdateGrabs();
}
/*
@ -1363,8 +1357,8 @@ void Con_NotifyBox (const char *text)
Con_Printf ("Press a key.\n");
Con_Printf ("%s", Con_Quakebar(40)); //johnfitz
IN_Deactivate(modestate == MS_WINDOWED);
key_dest = key_console;
IN_UpdateGrabs();
Key_BeginInputGrab ();
do
@ -1380,9 +1374,9 @@ void Con_NotifyBox (const char *text)
Key_EndInputGrab ();
Con_Printf ("\n");
IN_Activate();
key_dest = key_game;
realtime = 0; // put the cursor back to invisible
IN_UpdateGrabs();
}

View file

@ -32,6 +32,7 @@ void Draw_Init (void);
void Draw_Character (int x, int y, int num);
void Draw_DebugChar (char num);
void Draw_Pic (int x, int y, qpic_t *pic);
void Draw_SubPic (float x, float y, float w, float h, qpic_t *pic, float s1, float t1, float s2, float t2);
void Draw_TransPicTranslate (int x, int y, qpic_t *pic, int top, int bottom); //johnfitz -- more parameters
void Draw_ConsoleBackground (void); //johnfitz -- removed parameter int lines
void Draw_TileClear (int x, int y, int w, int h);
@ -40,6 +41,7 @@ void Draw_FadeScreen (void);
void Draw_String (int x, int y, const char *str);
qpic_t *Draw_PicFromWad (const char *name);
qpic_t *Draw_CachePic (const char *path);
qpic_t *Draw_TryCachePic (const char *path);
void Draw_NewGame (void);
void GL_SetCanvas (canvastype newcanvas); //johnfitz

View file

@ -121,7 +121,7 @@ typedef struct cachepic_s
byte padding[32]; // for appended glpic
} cachepic_t;
#define MAX_CACHED_PICS 128
#define MAX_CACHED_PICS 512 //Spike -- increased to avoid csqc issues.
cachepic_t menu_cachepics[MAX_CACHED_PICS];
int menu_numcachepics;
@ -216,10 +216,21 @@ Draw_PicFromWad
*/
qpic_t *Draw_PicFromWad (const char *name)
{
int i;
cachepic_t *pic;
qpic_t *p;
glpic_t gl;
src_offset_t offset; //johnfitz
//Spike -- added cachepic stuff here, to avoid glitches if the function is called multiple times with the same image.
for (pic=menu_cachepics, i=0 ; i<menu_numcachepics ; pic++, i++)
{
if (!strcmp (name, pic->name))
return &pic->pic;
}
if (menu_numcachepics == MAX_CACHED_PICS)
Sys_Error ("menu_numcachepics == MAX_CACHED_PICS");
p = (qpic_t *) W_GetLumpName (name);
if (!p) return pic_nul; //johnfitz
@ -260,9 +271,25 @@ qpic_t *Draw_PicFromWad (const char *name)
gl.th = (float)p->height/(float)TexMgr_PadConditional(p->height); //johnfitz
}
memcpy (p->data, &gl, sizeof(glpic_t));
menu_numcachepics++;
strcpy (pic->name, name);
pic->pic = *p;
memcpy (pic->pic.data, &gl, sizeof(glpic_t));
return p;
return &pic->pic;
}
qpic_t *Draw_GetCachedPic (const char *path)
{
cachepic_t *pic;
int i;
for (pic=menu_cachepics, i=0 ; i<menu_numcachepics ; pic++, i++)
{
if (!strcmp (path, pic->name))
return &pic->pic;
}
return NULL;
}
/*
@ -270,7 +297,7 @@ qpic_t *Draw_PicFromWad (const char *name)
Draw_CachePic
================
*/
qpic_t *Draw_CachePic (const char *path)
qpic_t *Draw_TryCachePic (const char *path)
{
cachepic_t *pic;
int i;
@ -292,7 +319,7 @@ qpic_t *Draw_CachePic (const char *path)
//
dat = (qpic_t *)COM_LoadTempFile (path, NULL);
if (!dat)
Sys_Error ("Draw_CachePic: failed to load %s", path);
return NULL;
SwapPic (dat);
// HACK HACK HACK --- we need to keep the bytes for
@ -315,6 +342,14 @@ qpic_t *Draw_CachePic (const char *path)
return &pic->pic;
}
qpic_t *Draw_CachePic (const char *path)
{
qpic_t *pic = Draw_TryCachePic(path);
if (!pic)
Sys_Error ("Draw_CachePic: failed to load %s", path);
return pic;
}
/*
================
Draw_MakePic -- johnfitz -- generate pics from internal data
@ -523,6 +558,29 @@ void Draw_Pic (int x, int y, qpic_t *pic)
glEnd ();
}
void Draw_SubPic (float x, float y, float w, float h, qpic_t *pic, float s1, float t1, float s2, float t2)
{
glpic_t *gl;
s2 += s1;
t2 += t1;
if (scrap_dirty)
Scrap_Upload ();
gl = (glpic_t *)pic->data;
GL_Bind (gl->gltexture);
glBegin (GL_QUADS);
glTexCoord2f (gl->sl*(1-s1) + s1*gl->sh, gl->tl*(1-t1) + t1*gl->th);
glVertex2f (x, y);
glTexCoord2f (gl->sl*(1-s2) + s2*gl->sh, gl->tl*(1-t1) + t1*gl->th);
glVertex2f (x+w, y);
glTexCoord2f (gl->sl*(1-s2) + s2*gl->sh, gl->tl*(1-t2) + t2*gl->th);
glVertex2f (x+w, y+h);
glTexCoord2f (gl->sl*(1-s1) + s1*gl->sh, gl->tl*(1-t2) + t2*gl->th);
glVertex2f (x, y+h);
glEnd ();
}
/*
=============
Draw_TransPicTranslate -- johnfitz -- rewritten to use texmgr to do translation
@ -719,6 +777,11 @@ void GL_SetCanvas (canvastype newcanvas)
glOrtho (0, 640, 200, 0, -99999, 99999);
glViewport (glx + (glwidth - 320*s) / 2, gly + (glheight - 200*s) / 2, 640*s, 200*s);
break;
case CANVAS_CSQC:
s = CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0);
glOrtho (0, glwidth/s, glheight/s, 0, -99999, 99999);
glViewport (glx, gly, glwidth, glheight);
break;
case CANVAS_SBAR:
s = CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0);
if (cl.gametype == GAME_DEATHMATCH)

View file

@ -478,6 +478,8 @@ static bspx_header_t *bspxheader;
//unsupported lumps ('documented' elsewhere):
//BRUSHLIST (because hulls suck)
//LIGHTINGDIR (.lux)
//LIGHTING_E5BGR9 (hdr lighting)
//VERTEXNORMALS (smooth shading with dlights/rtlights)
static void *Q1BSPX_FindLump(char *lumpname, int *lumpsize)
{
int i;
@ -3149,6 +3151,10 @@ void Mod_LoadAliasModel (qmodel_t *mod, void *buffer)
Mod_CalcAliasBounds (pheader); //johnfitz
//Spike: for setmodel compat with vanilla
mod->clipmins[0] = mod->clipmins[1] = mod->clipmins[2] = -16;
mod->clipmaxs[0] = mod->clipmaxs[1] = mod->clipmaxs[2] = 16;
//
// build the draw lists
//

View file

@ -753,7 +753,7 @@ void R_ShowBoundingBoxes (void)
glDisable (GL_CULL_FACE);
glColor3f (1,1,1);
for (i=0, ed=NEXT_EDICT(sv.edicts) ; i<sv.num_edicts ; i++, ed=NEXT_EDICT(ed))
for (i=0, ed=NEXT_EDICT(qcvm->edicts) ; i<qcvm->num_edicts ; i++, ed=NEXT_EDICT(ed))
{
if (ed == sv_player)
continue; //don't draw player's own bbox

View file

@ -391,7 +391,7 @@ static void SCR_CalcRefdef (void)
size = scr_viewsize.value;
scale = CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0);
if (size >= 120 || cl.intermission || scr_sbaralpha.value < 1) //johnfitz -- scr_sbaralpha.value
if (size >= 120 || cl.intermission || (scr_sbaralpha.value < 1 || cl.qcvm.extfuncs.CSQC_DrawHud)) //johnfitz -- scr_sbaralpha.value. Spike -- simple csqc assumes fullscreen video the same way.
sb_lines = 0;
else if (size >= 110)
sb_lines = 24 * scale;

View file

@ -840,13 +840,7 @@ static void VID_Restart (void)
//
// update mouse grab
//
if (key_dest == key_console || key_dest == key_menu)
{
if (modestate == MS_WINDOWED)
IN_Deactivate(true);
else if (modestate == MS_FULLSCREEN)
IN_Activate();
}
IN_UpdateGrabs();
}
/*
@ -1397,6 +1391,15 @@ void VID_Shutdown (void)
}
}
void VID_SetWindowCaption(const char *newcaption)
{
#if defined(USE_SDL2)
SDL_SetWindowTitle(draw_context, newcaption);
#else
SDL_WM_SetCaption(newcaption, newcaption);
#endif
}
/*
===================================================================
@ -1802,14 +1805,7 @@ void VID_Toggle (void)
VID_SyncCvars();
// update mouse grab
if (key_dest == key_console || key_dest == key_menu)
{
if (modestate == MS_WINDOWED)
IN_Deactivate(true);
else if (modestate == MS_FULLSCREEN)
IN_Activate();
}
IN_UpdateGrabs();
}
else
{
@ -2231,7 +2227,7 @@ static void VID_MenuKey (int key)
Cbuf_AddText ("vid_restart\n");
key_dest = key_game;
m_state = m_none;
IN_Activate();
IN_UpdateGrabs();
break;
default:
break;
@ -2323,10 +2319,10 @@ VID_Menu_f
*/
static void VID_Menu_f (void)
{
IN_Deactivate(modestate == MS_WINDOWED);
key_dest = key_menu;
m_state = m_video;
m_entersound = true;
IN_UpdateGrabs();
//set all the cvars to match the current mode when entering the menu
VID_SyncCvars ();

View file

@ -62,6 +62,7 @@ cvar_t host_speeds = {"host_speeds","0",CVAR_NONE}; // set for running times
cvar_t host_maxfps = {"host_maxfps", "72", CVAR_ARCHIVE}; //johnfitz
cvar_t host_timescale = {"host_timescale", "0", CVAR_NONE}; //johnfitz
cvar_t max_edicts = {"max_edicts", "15000", CVAR_NONE}; //johnfitz //ericw -- changed from 2048 to 8192, removed CVAR_ARCHIVE
cvar_t cl_nocsqc = {"cl_nocsqc", "0", CVAR_NONE}; //spike -- blocks the loading of any csqc modules
cvar_t sys_ticrate = {"sys_ticrate","0.05",CVAR_NONE}; // dedicated server
cvar_t serverprofile = {"serverprofile","0",CVAR_NONE};
@ -124,6 +125,8 @@ void Host_EndGame (const char *message, ...)
va_end (argptr);
Con_DPrintf ("Host_EndGame: %s\n",string);
PR_SwitchQCVM(NULL);
if (sv.active)
Host_ShutdownServer (false);
@ -155,6 +158,8 @@ void Host_Error (const char *error, ...)
Sys_Error ("Host_Error: recursively entered");
inerror = true;
PR_SwitchQCVM(NULL);
SCR_EndLoadingPlaque (); // reenable screen updates
va_start (argptr,error);
@ -261,6 +266,7 @@ void Host_InitLocal (void)
Cvar_SetCallback (&host_maxfps, Max_Fps_f);
Cvar_RegisterVariable (&host_timescale); //johnfitz
Cvar_RegisterVariable (&cl_nocsqc); //spike
Cvar_RegisterVariable (&max_edicts); //johnfitz
Cvar_SetCallback (&max_edicts, Max_Edicts_f);
Cvar_RegisterVariable (&devstats); //johnfitz
@ -524,11 +530,13 @@ void Host_ShutdownServer(qboolean crash)
if (count)
Con_Printf("Host_ShutdownServer: NET_SendToAll failed for %u clients\n", count);
PR_SwitchQCVM(&sv.qcvm);
for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++)
if (host_client->active)
SV_DropClient(crash);
sv.worldmodel = NULL;
qcvm->worldmodel = NULL;
PR_SwitchQCVM(NULL);
//
// clear structures
@ -554,7 +562,8 @@ void Host_ClearMemory (void)
/* host_hunklevel MUST be set at this point */
Hunk_FreeToLowMark (host_hunklevel);
cls.signon = 0;
free(sv.edicts); // ericw -- sv.edicts switched to use malloc()
PR_ClearProgs(&sv.qcvm);
PR_ClearProgs(&cl.qcvm);
free(cl.static_entities);
free(sv.static_entities); //spike -- this is dynamic too, now
free(sv.ambientsounds);
@ -656,14 +665,14 @@ void Host_ServerFrame (void)
//johnfitz -- devstats
if (cls.signon == SIGNONS)
{
for (i=0, active=0; i<sv.num_edicts; i++)
for (i=0, active=0; i<qcvm->num_edicts; i++)
{
ent = EDICT_NUM(i);
if (!ent->free)
active++;
}
if (active > 600 && dev_peakstats.edicts <= 600)
Con_DWarning ("%i edicts exceeds standard limit of 600 (max = %d).\n", active, sv.max_edicts);
Con_DWarning ("%i edicts exceeds standard limit of 600 (max = %d).\n", active, qcvm->max_edicts);
dev_stats.edicts = active;
dev_peakstats.edicts = q_max(active, dev_peakstats.edicts);
}
@ -714,6 +723,46 @@ void _Host_Frame (float time)
{
if (CL_CheckDownloads())
{
PR_ClearProgs(&cl.qcvm);
if (pr_checkextension.value && !cl_nocsqc.value)
{ //only try to use csqc if qc extensions are enabled.
PR_SwitchQCVM(&cl.qcvm);
//try csprogs.dat first, then fall back on progs.dat in case someone tried merging the two.
//we only care about it if it actually contains a CSQC_DrawHud, otherwise its either just a (misnamed) ssqc progs or a full csqc progs that would just crash us on 3d stuff.
if ((PR_LoadProgs("csprogs.dat", false, pr_csqcbuiltins, pr_csqcnumbuiltins) && qcvm->extfuncs.CSQC_DrawHud)||
(PR_LoadProgs("progs.dat", false, pr_csqcbuiltins, pr_csqcnumbuiltins) && qcvm->extfuncs.CSQC_DrawHud))
{
qcvm->max_edicts = CLAMP (MIN_EDICTS,(int)max_edicts.value,MAX_EDICTS);
qcvm->edicts = (edict_t *) malloc (qcvm->max_edicts*qcvm->edict_size);
qcvm->num_edicts = qcvm->reserved_edicts = 1;
memset(qcvm->edicts, 0, qcvm->num_edicts*qcvm->edict_size);
//set a few globals, if they exist
if (qcvm->extglobals.maxclients)
*qcvm->extglobals.maxclients = cl.maxclients;
pr_global_struct->time = cl.time;
pr_global_struct->mapname = PR_SetEngineString(cl.mapname);
pr_global_struct->total_monsters = cl.statsf[STAT_TOTALMONSTERS];
pr_global_struct->total_secrets = cl.statsf[STAT_TOTALSECRETS];
pr_global_struct->deathmatch = cl.gametype;
pr_global_struct->coop = (cl.gametype == GAME_COOP) && cl.maxclients != 1;
if (qcvm->extglobals.player_localnum)
*qcvm->extglobals.player_localnum = cl.viewentity; //this is a guess, but is important for scoreboards.
//and call the init function... if it exists.
if (qcvm->extfuncs.CSQC_Init)
{
G_FLOAT(OFS_PARM0) = 0;
G_INT(OFS_PARM1) = PR_SetEngineString("QuakeSpasm-Spiked");
G_FLOAT(OFS_PARM2) = QUAKESPASM_VERSION;
PR_ExecuteProgram(qcvm->extfuncs.CSQC_Init);
}
}
else
PR_ClearProgs(qcvm);
PR_SwitchQCVM(NULL);
}
cl.sendprespawn = false;
MSG_WriteByte (&cls.message, clc_stringcmd);
MSG_WriteString (&cls.message, "prespawn");
@ -736,7 +785,11 @@ void _Host_Frame (float time)
Host_GetConsoleCommands ();
if (sv.active)
{
PR_SwitchQCVM(&sv.qcvm);
Host_ServerFrame ();
PR_SwitchQCVM(NULL);
}
//-------------------
//

View file

@ -464,10 +464,10 @@ void Host_Status_f (void)
j++;
if (j)
print_fn ( "effects: %i/%i\n", j, MAX_PARTICLETYPES-1);
for (i = 1,j=1; i < sv.num_edicts; i++)
if (!sv.edicts[i].free)
for (i = 1,j=1; i < sv.qcvm.num_edicts; i++)
if (!sv.qcvm.edicts[i].free)
j++;
print_fn ( "entities:%i/%i\n", j, sv.max_edicts);
print_fn ( "entities:%i/%i\n", j, sv.qcvm.max_edicts);
print_fn ( "players: %i active (%i max)\n\n", net_activeconnections, svs.maxclients);
for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++)
@ -840,9 +840,9 @@ void Host_Map_f (void)
CL_Disconnect ();
Host_ShutdownServer(false);
if (cls.state != ca_dedicated)
IN_Activate();
key_dest = key_game; // remove console or menu
if (cls.state != ca_dedicated)
IN_UpdateGrabs();
SCR_BeginLoadingPlaque ();
svs.serverflags = 0; // haven't completed an episode yet
@ -851,7 +851,9 @@ void Host_Map_f (void)
p = strstr(name, ".bsp");
if (p && p[4] == '\0')
*p = '\0';
PR_SwitchQCVM(&sv.qcvm);
SV_SpawnServer (name);
PR_SwitchQCVM(NULL);
if (!sv.active)
return;
@ -933,12 +935,15 @@ void Host_Changelevel_f (void)
Host_Error ("cannot find map %s", level);
//johnfitz
if (cls.state != ca_dedicated)
IN_Activate(); // -- S.A.
key_dest = key_game; // remove console or menu
if (cls.state != ca_dedicated)
IN_UpdateGrabs(); // -- S.A.
PR_SwitchQCVM(&sv.qcvm);
SV_SaveSpawnparms ();
q_strlcpy (level, Cmd_Argv(1), sizeof(level));
SV_SpawnServer (level);
PR_SwitchQCVM(NULL);
// also issue an error if spawn failed -- O.S.
if (!sv.active)
Host_Error ("cannot run map %s", level);
@ -966,7 +971,9 @@ void Host_Restart_f (void)
return;
}
q_strlcpy (mapname, sv.name, sizeof(mapname)); // mapname gets cleared in spawnserver
PR_SwitchQCVM(&sv.qcvm);
SV_SpawnServer (mapname);
PR_SwitchQCVM(NULL);
if (!sv.active)
Host_Error ("cannot restart map %s", mapname);
}
@ -1134,7 +1141,7 @@ void Host_Savegame_f (void)
fprintf (f, "%f\n", svs.clients->spawn_parms[i]);
fprintf (f, "%d\n", current_skill);
fprintf (f, "%s\n", sv.name);
fprintf (f, "%f\n",sv.time);
fprintf (f, "%f\n", qcvm->time);
// write the light styles
@ -1148,7 +1155,7 @@ void Host_Savegame_f (void)
ED_WriteGlobals (f);
for (i = 0; i < sv.num_edicts; i++)
for (i = 0; i < qcvm->num_edicts; i++)
{
ED_Write (f, EDICT_NUM(i));
fflush (f);
@ -1268,10 +1275,12 @@ void Host_Loadgame_f (void)
CL_Disconnect_f ();
PR_SwitchQCVM(&sv.qcvm);
SV_SpawnServer (mapname);
if (!sv.active)
{
PR_SwitchQCVM(NULL);
free (start);
start = NULL;
Con_Printf ("Couldn't load map\n");
@ -1369,12 +1378,12 @@ void Host_Loadgame_f (void)
else
{ // parse an edict
ent = EDICT_NUM(entnum);
if (entnum < sv.num_edicts) {
if (entnum < qcvm->num_edicts) {
ent->free = false;
memset (&ent->v, 0, progs->entityfields * 4);
memset (&ent->v, 0, qcvm->progs->entityfields * 4);
}
else {
memset (ent, 0, pr_edict_size);
memset (ent, 0, qcvm->edict_size);
}
data = ED_ParseEdict (data, ent);
@ -1386,8 +1395,8 @@ void Host_Loadgame_f (void)
entnum++;
}
sv.num_edicts = entnum;
sv.time = time;
qcvm->num_edicts = entnum;
qcvm->time = time;
free (start);
start = NULL;
@ -1395,6 +1404,8 @@ void Host_Loadgame_f (void)
for (i = 0; i < NUM_SPAWN_PARMS; i++)
svs.clients->spawn_parms[i] = spawn_parms[i];
PR_SwitchQCVM(NULL);
if (cls.state != ca_dedicated)
{
CL_EstablishConnection ("local");
@ -1674,7 +1685,7 @@ void Host_Kill_f (void)
return;
}
pr_global_struct->time = sv.time;
pr_global_struct->time = qcvm->time;
pr_global_struct->self = EDICT_TO_PROG(sv_player);
PR_ExecuteProgram (pr_global_struct->ClientKill);
}
@ -1783,7 +1794,7 @@ void Host_Spawn_f (void)
// set up the edict
ent = host_client->edict;
memset (&ent->v, 0, progs->entityfields * 4);
memset (&ent->v, 0, qcvm->progs->entityfields * 4);
ent->v.colormap = NUM_FOR_EDICT(ent);
ent->v.team = (host_client->colors & 15) + 1;
ent->v.netname = PR_SetEngineString(host_client->name);
@ -1792,11 +1803,11 @@ void Host_Spawn_f (void)
for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
(&pr_global_struct->parm1)[i] = host_client->spawn_parms[i];
// call the spawn function
pr_global_struct->time = sv.time;
pr_global_struct->time = qcvm->time;
pr_global_struct->self = EDICT_TO_PROG(sv_player);
PR_ExecuteProgram (pr_global_struct->ClientConnect);
if ((Sys_DoubleTime() - NET_QSocketGetTime(host_client->netconnection)) <= sv.time)
if ((Sys_DoubleTime() - NET_QSocketGetTime(host_client->netconnection)) <= qcvm->time)
Sys_Printf ("%s entered the game\n", host_client->name);
PR_ExecuteProgram (pr_global_struct->PutClientInServer);
@ -1808,7 +1819,7 @@ void Host_Spawn_f (void)
// send time of update
MSG_WriteByte (&host_client->message, svc_time);
MSG_WriteFloat (&host_client->message, sv.time);
MSG_WriteFloat (&host_client->message, qcvm->time);
if (host_client->protocol_pext2 & PEXT2_PREDINFO)
MSG_WriteShort(&host_client->message, (host_client->lastmovemessage&0xffff));
@ -2226,7 +2237,7 @@ edict_t *FindViewthing (void)
int i;
edict_t *e;
for (i=0 ; i<sv.num_edicts ; i++)
for (i=0 ; i<qcvm->num_edicts ; i++)
{
e = EDICT_NUM(i);
if ( !strcmp (PR_GetString(e->v.classname), "viewthing") )

View file

@ -33,6 +33,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
static qboolean textmode;
extern qboolean bind_grab; //from the menu code, so that we regrab the mouse in order to pass inputs through
static cvar_t in_debugkeys = {"in_debugkeys", "0", CVAR_NONE};
@ -199,8 +200,8 @@ static void IN_ReenableOSXMouseAccel (void)
}
#endif /* MACOS_X_ACCELERATION_HACK */
void IN_Activate (void)
#if 0
static void IN_Activate (void)
{
if (no_mouse)
return;
@ -238,7 +239,7 @@ void IN_Activate (void)
total_dy = 0;
}
void IN_Deactivate (qboolean free_cursor)
static void IN_Deactivate (qboolean free_cursor)
{
if (no_mouse)
return;
@ -270,7 +271,84 @@ void IN_Deactivate (qboolean free_cursor)
}
/* discard all mouse events when input is deactivated */
IN_BeginIgnoringMouseEvents();
if (cl.qcvm.extfuncs.CSQC_InputEvent && free_cursor)
IN_EndIgnoringMouseEvents();
else
IN_BeginIgnoringMouseEvents();
}
#endif
static void IN_UpdateGrabs_Internal(qboolean forecerelease)
{
qboolean wantcursor; //we're trying to get a cursor here...
qboolean freemouse; //the OS should have a free cursor too...
qboolean needevents; //whether we want to receive events still
wantcursor = (key_dest == key_console || (key_dest == key_menu&&!bind_grab)) || (key_dest == key_game && cl.csqc_cursorforced);
freemouse = wantcursor && (modestate == MS_WINDOWED || key_dest == key_game && cl.csqc_cursorforced);
needevents = (!wantcursor) || key_dest == key_game;
if (forecerelease)
needevents = freemouse = wantcursor = true;
#ifdef MACOS_X_ACCELERATION_HACK
if (!freemouse)
{ /* Save the status of mouse acceleration */
if (originalMouseSpeed == -1 && in_disablemacosxmouseaccel.value)
IN_DisableOSXMouseAccel();
}
else if (originalMouseSpeed != -1)
IN_ReenableOSXMouseAccel();
#endif
#if defined(USE_SDL2)
if (SDL_SetRelativeMouseMode(freemouse?SDL_FALSE:SDL_TRUE) != 0)
{
Con_Printf("WARNING: SDL_SetRelativeMouseMode(%s) failed.\n", freemouse?"SDL_FALSE":"SDL_TRUE");
}
#else
if (freemouse)
{
if (SDL_WM_GrabInput(SDL_GRAB_QUERY) != SDL_GRAB_OFF)
{
SDL_WM_GrabInput(SDL_GRAB_OFF);
if (SDL_WM_GrabInput(SDL_GRAB_QUERY) != SDL_GRAB_OFF)
Con_Printf("WARNING: SDL_WM_GrabInput(SDL_GRAB_OFF) failed.\n");
}
if (SDL_ShowCursor(SDL_QUERY) != SDL_ENABLE)
{
SDL_ShowCursor(SDL_ENABLE);
if (SDL_ShowCursor(SDL_QUERY) != SDL_ENABLE)
Con_Printf("WARNING: SDL_ShowCursor(SDL_ENABLE) failed.\n");
}
}
else
{
if (SDL_WM_GrabInput(SDL_GRAB_QUERY) != SDL_GRAB_ON)
{
SDL_WM_GrabInput(SDL_GRAB_ON);
if (SDL_WM_GrabInput(SDL_GRAB_QUERY) != SDL_GRAB_ON)
Con_Printf("WARNING: SDL_WM_GrabInput(SDL_GRAB_ON) failed.\n");
}
if (SDL_ShowCursor(SDL_QUERY) != SDL_DISABLE)
{
SDL_ShowCursor(SDL_DISABLE);
if (SDL_ShowCursor(SDL_QUERY) != SDL_DISABLE)
Con_Printf("WARNING: SDL_ShowCursor(SDL_DISABLE) failed.\n");
}
}
#endif
if (needevents)
IN_EndIgnoringMouseEvents();
else
IN_BeginIgnoringMouseEvents();
}
void IN_UpdateGrabs(void)
{
IN_UpdateGrabs_Internal(false);
}
void IN_StartupJoystick (void)
@ -375,13 +453,13 @@ void IN_Init (void)
Cvar_RegisterVariable(&joy_swapmovelook);
Cvar_RegisterVariable(&joy_enable);
IN_Activate();
IN_UpdateGrabs();
IN_StartupJoystick();
}
void IN_Shutdown (void)
{
IN_Deactivate(true);
IN_UpdateGrabs();
IN_ShutdownJoystick();
}
@ -389,8 +467,36 @@ extern cvar_t cl_maxpitch; /* johnfitz -- variable pitch clamping */
extern cvar_t cl_minpitch; /* johnfitz -- variable pitch clamping */
void IN_MouseMotion(int dx, int dy)
void IN_MouseMotion(int dx, int dy, int wx, int wy)
{
if (key_dest != key_game && key_dest != key_message)
dx = dy = 0;
else if (cl.qcvm.extfuncs.CSQC_InputEvent)
{
PR_SwitchQCVM(&cl.qcvm);
if (cl.csqc_cursorforced)
{
float s = CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0);
wx /= s;
wy /= s;
G_FLOAT(OFS_PARM0) = CSIE_MOUSEABS;
G_VECTORSET(OFS_PARM1, wx, wy, 0); //x
G_VECTORSET(OFS_PARM2, wy, 0, 0); //y
G_VECTORSET(OFS_PARM3, 0, 0, 0); //devid
}
else
{
G_FLOAT(OFS_PARM0) = CSIE_MOUSEDELTA;
G_VECTORSET(OFS_PARM1, dx, dy, 0); //x
G_VECTORSET(OFS_PARM2, dy, 0, 0); //y
G_VECTORSET(OFS_PARM3, 0, 0, 0); //devid
}
PR_ExecuteProgram(cl.qcvm.extfuncs.CSQC_InputEvent);
if (G_FLOAT(OFS_RETURN) || cl.csqc_cursorforced)
dx = dy = 0; //if the qc says it handled it, swallow the movement.
PR_SwitchQCVM(NULL);
}
total_dx += dx;
total_dy += dy;
}
@ -684,8 +790,8 @@ void IN_JoyMove (usercmd_t *cmd)
cmd->sidemove += (cl_sidespeed.value * speed * moveEased.x);
cmd->forwardmove -= (cl_forwardspeed.value * speed * moveEased.y);
cl.viewangles[YAW] -= lookEased.x * joy_sensitivity_yaw.value * host_frametime;
cl.viewangles[PITCH] += lookEased.y * joy_sensitivity_pitch.value * (joy_invert.value ? -1.0 : 1.0) * host_frametime;
cl.viewangles[YAW] -= lookEased.x * joy_sensitivity_yaw.value * host_frametime * cl.csqc_sensitivity;
cl.viewangles[PITCH] += lookEased.y * joy_sensitivity_pitch.value * (joy_invert.value ? -1.0 : 1.0) * host_frametime * cl.csqc_sensitivity;
if (lookEased.x != 0 || lookEased.y != 0)
V_StopPitchDrift();
@ -711,7 +817,7 @@ void IN_MouseMove(usercmd_t *cmd)
if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
cmd->sidemove += m_side.value * dmx;
else
cl.viewangles[YAW] -= m_yaw.value * dmx;
cl.viewangles[YAW] -= m_yaw.value * dmx * cl.csqc_sensitivity;
if (in_mlook.state & 1)
{
@ -721,7 +827,7 @@ void IN_MouseMove(usercmd_t *cmd)
if ( (in_mlook.state & 1) && !(in_strafe.state & 1))
{
cl.viewangles[PITCH] += m_pitch.value * dmy;
cl.viewangles[PITCH] += m_pitch.value * dmy * cl.csqc_sensitivity;
/* johnfitz -- variable pitch clamping */
if (cl.viewangles[PITCH] > cl_maxpitch.value)
cl.viewangles[PITCH] = cl_maxpitch.value;
@ -1004,6 +1110,8 @@ void IN_SendKeyEvents (void)
int key;
qboolean down;
IN_UpdateGrabs();
while (SDL_PollEvent(&event))
{
switch (event.type)
@ -1098,7 +1206,7 @@ void IN_SendKeyEvents (void)
#endif
case SDL_MOUSEMOTION:
IN_MouseMotion(event.motion.xrel, event.motion.yrel);
IN_MouseMotion(event.motion.xrel, event.motion.yrel, event.motion.x, event.motion.y);
break;
#if defined(USE_SDL2)

View file

@ -32,7 +32,7 @@ void IN_Commands (void);
// oportunity for devices to stick commands on the script buffer
// mouse moved by dx and dy pixels
void IN_MouseMotion(int dx, int dy);
void IN_MouseMotion(int dx, int dy, int wx, int wy);
void IN_SendKeyEvents (void);
@ -47,11 +47,9 @@ void IN_Move (usercmd_t *cmd);
void IN_ClearStates (void);
// restores all button and position states to defaults
// called when the app becomes active
void IN_Activate ();
// called when the app becomes inactive
void IN_Deactivate (qboolean free_cursor);
// spike - called whenever mouse focus etc has changed (including console toggled). this is optional, but there's still a number of blocking commands, like connect
// doing all the mode, state, etc checks in one place ensures that they're consistent, regardless of what else is happening.
void IN_UpdateGrabs(void);
#endif /* _QUAKE_INPUT_H */

View file

@ -174,6 +174,326 @@ keyname_t keynames[] =
{NULL, 0}
};
//QC key codes are based upon DP's keycode constants. This is on account of menu.dat coming first.
int Key_NativeToQC(int code)
{
switch(code)
{
case K_TAB: return 9;
case K_ENTER: return 13;
case K_ESCAPE: return 27;
case K_SPACE: return 32;
case K_BACKSPACE: return 127;
case K_UPARROW: return 128;
case K_DOWNARROW: return 129;
case K_LEFTARROW: return 130;
case K_RIGHTARROW: return 131;
case K_ALT: return 132;
case K_CTRL: return 133;
case K_SHIFT: return 134;
case K_F1: return 135;
case K_F2: return 136;
case K_F3: return 137;
case K_F4: return 138;
case K_F5: return 139;
case K_F6: return 140;
case K_F7: return 141;
case K_F8: return 142;
case K_F9: return 143;
case K_F10: return 144;
case K_F11: return 145;
case K_F12: return 146;
case K_INS: return 147;
case K_DEL: return 148;
case K_PGDN: return 149;
case K_PGUP: return 150;
case K_HOME: return 151;
case K_END: return 152;
case K_PAUSE: return 153;
case K_KP_NUMLOCK: return 154;
// case K_CAPSLOCK: return 155;
// case K_SCRLCK: return 156;
case K_KP_INS: return 157;
case K_KP_END: return 158;
case K_KP_DOWNARROW: return 159;
case K_KP_PGDN: return 160;
case K_KP_LEFTARROW: return 161;
case K_KP_5: return 162;
case K_KP_RIGHTARROW: return 163;
case K_KP_HOME: return 164;
case K_KP_UPARROW: return 165;
case K_KP_PGUP: return 166;
case K_KP_DEL: return 167;
case K_KP_SLASH: return 168;
case K_KP_STAR: return 169;
case K_KP_MINUS: return 170;
case K_KP_PLUS: return 171;
case K_KP_ENTER: return 172;
// case K_KP_EQUALS: return 173;
// case K_PRINTSCREEN: return 174;
case K_MOUSE1: return 512;
case K_MOUSE2: return 513;
case K_MOUSE3: return 514;
case K_MWHEELUP: return 515;
case K_MWHEELDOWN: return 516;
case K_MOUSE4: return 517;
case K_MOUSE5: return 518;
// case K_MOUSE6: return 519;
// case K_MOUSE7: return 520;
// case K_MOUSE8: return 521;
// case K_MOUSE9: return 522;
// case K_MOUSE10: return 523;
// case K_MOUSE11: return 524;
// case K_MOUSE12: return 525;
// case K_MOUSE13: return 526;
// case K_MOUSE14: return 527;
// case K_MOUSE15: return 528;
// case K_MOUSE16: return 529;
case K_JOY1: return 768;
case K_JOY2: return 769;
case K_JOY3: return 770;
case K_JOY4: return 771;
// case K_JOY5: return 772;
// case K_JOY6: return 773;
// case K_JOY7: return 774;
// case K_JOY8: return 775;
// case K_JOY9: return 776;
// case K_JOY10: return 777;
// case K_JOY11: return 778;
// case K_JOY12: return 779;
// case K_JOY13: return 780;
// case K_JOY14: return 781;
// case K_JOY15: return 782;
// case K_JOY16: return 783;
case K_AUX1: return 784;
case K_AUX2: return 785;
case K_AUX3: return 786;
case K_AUX4: return 787;
case K_AUX5: return 788;
case K_AUX6: return 789;
case K_AUX7: return 790;
case K_AUX8: return 791;
case K_AUX9: return 792;
case K_AUX10: return 793;
case K_AUX11: return 794;
case K_AUX12: return 795;
case K_AUX13: return 796;
case K_AUX14: return 797;
case K_AUX15: return 798;
case K_AUX16: return 799;
case K_AUX17: return 800;
case K_AUX18: return 801;
case K_AUX19: return 802;
case K_AUX20: return 803;
case K_AUX21: return 804;
case K_AUX22: return 805;
case K_AUX23: return 806;
case K_AUX24: return 807;
case K_AUX25: return 808;
case K_AUX26: return 809;
case K_AUX27: return 810;
case K_AUX28: return 811;
case K_AUX29: return 812;
case K_AUX30: return 813;
case K_AUX31: return 814;
case K_AUX32: return 815;
// case K_GP_DPAD_UP: return 816;
// case K_GP_DPAD_DOWN: return 817;
// case K_GP_DPAD_LEFT: return 818;
// case K_GP_DPAD_RIGHT: return 819;
// case K_GP_START: return 820;
// case K_GP_BACK: return 821;
case K_LTHUMB: return 822;
case K_RTHUMB: return 823;
case K_LSHOULDER: return 824;
case K_RSHOULDER: return 825;
case K_ABUTTON: return 826;
case K_BBUTTON: return 827;
case K_XBUTTON: return 828;
case K_YBUTTON: return 829;
case K_LTRIGGER: return 830;
case K_RTRIGGER: return 831;
default:
//ascii chars are mapped as-is (yes this means upper-case keys don't get used).
if (code >= 0 && code < 127)
return code;
return -code; //qc doesn't have extended keys available to it.
}
}
int Key_QCToNative(int code)
{
switch(code)
{
case 9: return K_TAB;
case 13: return K_ENTER;
case 27: return K_ESCAPE;
case 32: return K_SPACE;
case 127: return K_BACKSPACE;
case 128: return K_UPARROW;
case 129: return K_DOWNARROW;
case 130: return K_LEFTARROW;
case 131: return K_RIGHTARROW;
case 132: return K_ALT;
case 133: return K_CTRL;
case 134: return K_SHIFT;
case 135: return K_F1;
case 136: return K_F2;
case 137: return K_F3;
case 138: return K_F4;
case 139: return K_F5;
case 140: return K_F6;
case 141: return K_F7;
case 142: return K_F8;
case 143: return K_F9;
case 144: return K_F10;
case 145: return K_F11;
case 146: return K_F12;
case 147: return K_INS;
case 148: return K_DEL;
case 149: return K_PGDN;
case 150: return K_PGUP;
case 151: return K_HOME;
case 152: return K_END;
case 153: return K_PAUSE;
case 154: return K_KP_NUMLOCK;
// case 155: return K_CAPSLOCK;
// case 156: return K_SCRLCK;
case 157: return K_KP_INS;
case 158: return K_KP_END;
case 159: return K_KP_DOWNARROW;
case 160: return K_KP_PGDN;
case 161: return K_KP_LEFTARROW;
case 162: return K_KP_5;
case 163: return K_KP_RIGHTARROW;
case 164: return K_KP_HOME;
case 165: return K_KP_UPARROW;
case 166: return K_KP_PGUP;
case 167: return K_KP_DEL;
case 168: return K_KP_SLASH;
case 169: return K_KP_STAR;
case 170: return K_KP_MINUS;
case 171: return K_KP_PLUS;
case 172: return K_KP_ENTER;
// case 173: return K_KP_EQUALS;
// case 174: return K_PRINTSCREEN;
case 512: return K_MOUSE1;
case 513: return K_MOUSE2;
case 514: return K_MOUSE3;
case 515: return K_MWHEELUP;
case 516: return K_MWHEELDOWN;
case 517: return K_MOUSE4;
case 518: return K_MOUSE5;
// case 519: return K_MOUSE6;
// case 520: return K_MOUSE7;
// case 521: return K_MOUSE8;
// case 522: return K_MOUSE9;
// case 523: return K_MOUSE10;
// case 524: return K_MOUSE11;
// case 525: return K_MOUSE12;
// case 526: return K_MOUSE13;
// case 527: return K_MOUSE14;
// case 528: return K_MOUSE15;
// case 529: return K_MOUSE16;
case 768: return K_JOY1;
case 769: return K_JOY2;
case 770: return K_JOY3;
case 771: return K_JOY4;
// case 772: return K_JOY5;
// case 773: return K_JOY6;
// case 774: return K_JOY7;
// case 775: return K_JOY8;
// case 776: return K_JOY9;
// case 777: return K_JOY10;
// case 778: return K_JOY11;
// case 779: return K_JOY12;
// case 780: return K_JOY13;
// case 781: return K_JOY14;
// case 782: return K_JOY15;
// case 783: return K_JOY16;
case 784: return K_AUX1;
case 785: return K_AUX2;
case 786: return K_AUX3;
case 787: return K_AUX4;
case 788: return K_AUX5;
case 789: return K_AUX6;
case 790: return K_AUX7;
case 791: return K_AUX8;
case 792: return K_AUX9;
case 793: return K_AUX10;
case 794: return K_AUX11;
case 795: return K_AUX12;
case 796: return K_AUX13;
case 797: return K_AUX14;
case 798: return K_AUX15;
case 799: return K_AUX16;
case 800: return K_AUX17;
case 801: return K_AUX18;
case 802: return K_AUX19;
case 803: return K_AUX20;
case 804: return K_AUX21;
case 805: return K_AUX22;
case 806: return K_AUX23;
case 807: return K_AUX24;
case 808: return K_AUX25;
case 809: return K_AUX26;
case 810: return K_AUX27;
case 811: return K_AUX28;
case 812: return K_AUX29;
case 813: return K_AUX30;
case 814: return K_AUX31;
case 815: return K_AUX32;
// case 816: return K_GP_DPAD_UP;
// case 817: return K_GP_DPAD_DOWN;
// case 818: return K_GP_DPAD_LEFT;
// case 819: return K_GP_DPAD_RIGHT;
// case 820: return K_GP_START;
// case 821: return K_GP_BACK;
case 822: return K_LTHUMB;
case 823: return K_RTHUMB;
case 824: return K_LSHOULDER;
case 825: return K_RSHOULDER;
case 826: return K_ABUTTON;
case 827: return K_BBUTTON;
case 828: return K_XBUTTON;
case 829: return K_YBUTTON;
case 830: return K_LTRIGGER;
case 831: return K_RTRIGGER;
// case 832: return K_GP_LEFT_THUMB_UP;
// case 833: return K_GP_LEFT_THUMB_DOWN;
// case 834: return K_GP_LEFT_THUMB_LEFT;
// case 835: return K_GP_LEFT_THUMB_RIGHT;
// case 836: return K_GP_RIGHT_THUMB_UP;
// case 837: return K_GP_RIGHT_THUMB_DOWN;
// case 838: return K_GP_RIGHT_THUMB_LEFT;
// case 839: return K_GP_RIGHT_THUMB_RIGHT;
default:
//ascii chars are mapped as-is (yes this means upper-case keys don't get used).
if (code >= 0 && code < 127)
return code;
else if (code < 0)
{
code = -code;
if (code < 0 || code >= MAX_KEYS)
code = -1; //was invalid somehow... don't crash anything.
return code; //qc doesn't have extended keys available to it. so map negative keys back to native ones.
}
else
return -code; //this qc keycode has no native equivelent. use negatives, because we can.
}
}
/*
==============================================================================
@ -931,6 +1251,23 @@ void Key_GetGrabbedInput (int *lastkey, int *lastchar)
*lastchar = key_inputgrab.lastchar;
}
qboolean CSQC_HandleKeyEvent(qboolean down, int keyc, int unic)
{
qboolean inhibit = false;
if (cl.qcvm.extfuncs.CSQC_InputEvent && key_dest == key_game)
{
PR_SwitchQCVM(&cl.qcvm);
G_FLOAT(OFS_PARM0) = down?CSIE_KEYDOWN:CSIE_KEYUP;
G_VECTORSET(OFS_PARM1, Key_NativeToQC(keyc), 0, 0); //x
G_VECTORSET(OFS_PARM2, unic, 0, 0); //y
G_VECTORSET(OFS_PARM3, 0, 0, 0); //devid
PR_ExecuteProgram(cl.qcvm.extfuncs.CSQC_InputEvent);
inhibit = G_FLOAT(OFS_RETURN);
PR_SwitchQCVM(NULL);
}
return inhibit;
}
/*
===================
Key_Event
@ -981,7 +1318,10 @@ void Key_Event (int key, qboolean down)
if (key == K_ESCAPE)
{
if (!down)
{
CSQC_HandleKeyEvent(down, key, 0); //Spike -- for consistency
return;
}
if (keydown[K_SHIFT])
{
@ -999,6 +1339,8 @@ void Key_Event (int key, qboolean down)
break;
case key_game:
case key_console:
if (CSQC_HandleKeyEvent(down, key, 0)) //Spike -- CSQC needs to be able to intercept escape. Note that shift+escape will always give the console for buggy mods.
break;
M_ToggleMenu_f ();
break;
default:
@ -1008,6 +1350,10 @@ void Key_Event (int key, qboolean down)
return;
}
//Spike -- give csqc a change to handle (and swallow) key events.
if (CSQC_HandleKeyEvent(down, key, 0))
return;
// key up events only generate commands if the game key binding is
// a button command (leading + sign). These will occur even in console mode,
// to keep the character from continuing an action started before a console
@ -1180,16 +1526,16 @@ void Key_UpdateForDest (void)
if (forced && cls.state == ca_connected)
{
forced = false;
IN_Activate();
key_dest = key_game;
IN_UpdateGrabs();
}
break;
case key_game:
if (cls.state != ca_connected)
{
forced = true;
IN_Deactivate(modestate == MS_WINDOWED);
key_dest = key_console;
IN_UpdateGrabs();
break;
}
/* fallthrough */

View file

@ -187,6 +187,9 @@ qboolean Key_TextEntry (void);
void Key_SetBinding (int keynum, const char *binding);
const char *Key_KeynumToString (int keynum);
int Key_StringToKeynum (const char *str);
int Key_NativeToQC(int code);
int Key_QCToNative(int code); //warning: will return negative values for unknown qc keys.
void Key_WriteBindings (FILE *f);
void Key_EndChat (void);

View file

@ -218,9 +218,10 @@ void M_ToggleMenu_f (void)
return;
}
IN_Activate();
key_dest = key_game;
m_state = m_none;
IN_UpdateGrabs();
return;
}
if (key_dest == key_console)
@ -248,10 +249,11 @@ void M_Menu_Main_f (void)
m_save_demonum = cls.demonum;
cls.demonum = -1;
}
IN_Deactivate(modestate == MS_WINDOWED);
key_dest = key_menu;
m_state = m_main;
m_entersound = true;
IN_UpdateGrabs();
}
@ -277,10 +279,10 @@ void M_Main_Key (int key)
{
case K_ESCAPE:
case K_BBUTTON:
IN_Activate();
key_dest = key_game;
m_state = m_none;
cls.demonum = m_save_demonum;
IN_UpdateGrabs();
if (!fitzmode) /* QuakeSpasm customization: */
break;
if (cls.demonum != -1 && !cls.demoplayback && cls.state != ca_connected)
@ -338,10 +340,11 @@ int m_singleplayer_cursor;
void M_Menu_SinglePlayer_f (void)
{
IN_Deactivate(modestate == MS_WINDOWED);
key_dest = key_menu;
m_state = m_singleplayer;
m_entersound = true;
IN_UpdateGrabs();
}
@ -393,8 +396,8 @@ void M_SinglePlayer_Key (int key)
if (sv.active)
if (!SCR_ModalMessage("Are you sure you want to\nstart a new game?\n", 0.0f))
break;
IN_Activate();
key_dest = key_game;
IN_UpdateGrabs();
if (sv.active)
Cbuf_AddText ("disconnect\n");
Cbuf_AddText ("maxplayers 1\n");
@ -459,9 +462,10 @@ void M_Menu_Load_f (void)
m_entersound = true;
m_state = m_load;
IN_Deactivate(modestate == MS_WINDOWED);
key_dest = key_menu;
M_ScanSaves ();
IN_UpdateGrabs();
}
@ -476,8 +480,8 @@ void M_Menu_Save_f (void)
m_entersound = true;
m_state = m_save;
IN_Deactivate(modestate == MS_WINDOWED);
key_dest = key_menu;
IN_UpdateGrabs();
M_ScanSaves ();
}
@ -530,8 +534,8 @@ void M_Load_Key (int k)
if (!loadable[load_cursor])
return;
m_state = m_none;
IN_Activate();
key_dest = key_game;
IN_UpdateGrabs();
// Host_Loadgame_f can't bring up the loading plaque because too much
// stack space has been used, so do it now
@ -573,8 +577,8 @@ void M_Save_Key (int k)
case K_KP_ENTER:
case K_ABUTTON:
m_state = m_none;
IN_Activate();
key_dest = key_game;
IN_UpdateGrabs();
Cbuf_AddText (va("save s%i\n", load_cursor));
return;
@ -605,10 +609,10 @@ int m_multiplayer_cursor;
void M_Menu_MultiPlayer_f (void)
{
IN_Deactivate(modestate == MS_WINDOWED);
key_dest = key_menu;
m_state = m_multiplayer;
m_entersound = true;
IN_UpdateGrabs();
}
@ -693,7 +697,6 @@ int setup_bottom;
void M_Menu_Setup_f (void)
{
IN_Deactivate(modestate == MS_WINDOWED);
key_dest = key_menu;
m_state = m_setup;
m_entersound = true;
@ -701,6 +704,8 @@ void M_Menu_Setup_f (void)
Q_strcpy(setup_hostname, hostname.string);
setup_top = setup_oldtop = ((int)cl_color.value) >> 4;
setup_bottom = setup_oldbottom = ((int)cl_color.value) & 15;
IN_UpdateGrabs();
}
@ -883,12 +888,13 @@ const char *net_helpMessage [] =
void M_Menu_Net_f (void)
{
IN_Deactivate(modestate == MS_WINDOWED);
key_dest = key_menu;
m_state = m_net;
m_entersound = true;
m_net_items = 2;
IN_UpdateGrabs();
if (m_net_cursor >= m_net_items)
m_net_cursor = 0;
m_net_cursor--;
@ -1012,10 +1018,11 @@ int options_cursor;
void M_Menu_Options_f (void)
{
IN_Deactivate(modestate == MS_WINDOWED);
key_dest = key_menu;
m_state = m_options;
m_entersound = true;
IN_UpdateGrabs();
}
@ -1368,7 +1375,7 @@ static size_t numbindnames;
static size_t keys_first;
static size_t keys_cursor;
static qboolean bind_grab;
qboolean bind_grab;
void M_Keys_Close (void)
{
@ -1429,10 +1436,10 @@ void M_Keys_Populate(void)
void M_Menu_Keys_f (void)
{
IN_Deactivate(modestate == MS_WINDOWED);
key_dest = key_menu;
m_state = m_keys;
m_entersound = true;
IN_UpdateGrabs();
M_Keys_Populate();
}
@ -1570,7 +1577,7 @@ void M_Keys_Key (int k)
}
bind_grab = false;
IN_Deactivate(modestate == MS_WINDOWED); // deactivate because we're returning to the menu
IN_UpdateGrabs();
return;
}
@ -1622,7 +1629,7 @@ void M_Keys_Key (int k)
if (keys[2] != -1)
M_UnbindCommand (bindnames[keys_cursor].cmd);
bind_grab = true;
IN_Activate(); // activate to allow mouse key binding
IN_UpdateGrabs(); // activate to allow mouse key binding
break;
case K_BACKSPACE: // delete bindings
@ -1662,11 +1669,11 @@ int help_page;
void M_Menu_Help_f (void)
{
IN_Deactivate(modestate == MS_WINDOWED);
key_dest = key_menu;
m_state = m_help;
m_entersound = true;
help_page = 0;
IN_UpdateGrabs();
}
@ -1715,12 +1722,13 @@ void M_Menu_Quit_f (void)
if (m_state == m_quit)
return;
wasInMenus = (key_dest == key_menu);
IN_Deactivate(modestate == MS_WINDOWED);
key_dest = key_menu;
m_quit_prevstate = m_state;
m_state = m_quit;
m_entersound = true;
msgNumber = rand()&7;
IN_UpdateGrabs();
}
@ -1735,9 +1743,9 @@ void M_Quit_Key (int key)
}
else
{
IN_Activate();
key_dest = key_game;
m_state = m_none;
IN_UpdateGrabs();
}
}
}
@ -1756,17 +1764,17 @@ void M_Quit_Char (int key)
}
else
{
IN_Activate();
key_dest = key_game;
m_state = m_none;
IN_UpdateGrabs();
}
break;
case 'y':
case 'Y':
IN_Deactivate(modestate == MS_WINDOWED);
key_dest = key_console;
Host_Quit_f ();
IN_UpdateGrabs();
break;
default:
@ -1825,7 +1833,6 @@ char lanConfig_joinname[22];
void M_Menu_LanConfig_f (void)
{
IN_Deactivate(modestate == MS_WINDOWED);
key_dest = key_menu;
m_state = m_lanconfig;
m_entersound = true;
@ -1843,6 +1850,7 @@ void M_Menu_LanConfig_f (void)
m_return_onerror = false;
m_return_reason[0] = 0;
IN_UpdateGrabs();
}
@ -1969,9 +1977,9 @@ void M_LanConfig_Key (int key)
{
m_return_state = m_state;
m_return_onerror = true;
IN_Activate();
key_dest = key_game;
m_state = m_none;
IN_UpdateGrabs();
Cbuf_AddText ( va ("connect \"%s\"\n", lanConfig_joinname) );
}
}
@ -2200,9 +2208,9 @@ double m_serverInfoMessageTime;
void M_Menu_GameOptions_f (void)
{
IN_Deactivate(modestate == MS_WINDOWED);
key_dest = key_menu;
m_state = m_gameoptions;
IN_UpdateGrabs();
m_entersound = true;
if (maxplayers == 0)
maxplayers = svs.maxclients;
@ -2531,9 +2539,9 @@ enum slistScope_e searchLastScope = SLIST_LAN;
void M_Menu_Search_f (enum slistScope_e scope)
{
IN_Deactivate(modestate == MS_WINDOWED);
key_dest = key_menu;
m_state = m_search;
IN_UpdateGrabs();
m_entersound = false;
slistSilent = true;
slistScope = searchLastScope = scope;
@ -2593,9 +2601,9 @@ qboolean slist_sorted;
void M_Menu_ServerList_f (void)
{
IN_Deactivate(modestate == MS_WINDOWED);
key_dest = key_menu;
m_state = m_slist;
IN_UpdateGrabs();
m_entersound = true;
slist_cursor = 0;
slist_first = 0;
@ -2671,9 +2679,9 @@ void M_ServerList_Key (int k)
m_return_state = m_state;
m_return_onerror = true;
slist_sorted = false;
IN_Activate();
key_dest = key_game;
m_state = m_none;
IN_UpdateGrabs();
Cbuf_AddText ( va ("connect \"%s\"\n", NET_SlistPrintServerName(slist_cursor)) );
break;

View file

@ -2244,10 +2244,11 @@ ErrorReturn2:
dfunc.Close_Socket(newsock);
if (m_return_onerror)
{
IN_Deactivate(modestate == MS_WINDOWED);
key_dest = key_menu;
m_state = m_return_state;
m_return_onerror = false;
IN_UpdateGrabs();
}
return NULL;
}

View file

@ -32,7 +32,7 @@ char *PR_GetTempString (void)
return pr_string_temp[(STRINGTEMP_BUFFERS-1) & ++pr_string_tempindex];
}
#define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
#define RETURN_EDICT(e) (((int *)qcvm->globals)[OFS_RETURN] = EDICT_TO_PROG(e))
#define MSG_BROADCAST 0 // unreliable to all
#define MSG_ONE 1 // reliable to one (msg_entity)
@ -57,7 +57,7 @@ char *PF_VarString (int first)
out[0] = 0;
s = 0;
for (i = first; i < pr_argc; i++)
for (i = first; i < qcvm->argc; i++)
{
s = q_strlcat(out, G_STRING((OFS_PARM0+i*3)), sizeof(out));
if (s >= sizeof(out))
@ -95,7 +95,7 @@ static void PF_error (void)
s = PF_VarString(0);
Con_Printf ("======SERVER ERROR in %s:\n%s\n",
PR_GetString(pr_xfunction->s_name), s);
PR_GetString(qcvm->xfunction->s_name), s);
ed = PROG_TO_EDICT(pr_global_struct->self);
ED_Print (ed);
@ -119,7 +119,7 @@ static void PF_objerror (void)
s = PF_VarString(0);
Con_Printf ("======OBJECT ERROR in %s:\n%s\n",
PR_GetString(pr_xfunction->s_name), s);
PR_GetString(qcvm->xfunction->s_name), s);
ed = PROG_TO_EDICT(pr_global_struct->self);
ED_Print (ed);
ED_Free (ed);
@ -168,7 +168,7 @@ static void PF_setorigin (void)
}
static void SetMinMaxSize (edict_t *e, float *minvec, float *maxvec, qboolean rotate)
void SetMinMaxSize (edict_t *e, float *minvec, float *maxvec, qboolean rotate)
{
float *angles;
vec3_t rmin, rmax;
@ -270,7 +270,8 @@ PF_setmodel
setmodel(entity, model)
=================
*/
static void PF_setmodel (void)
cvar_t sv_gameplayfix_setmodelrealbox = {"sv_gameplayfix_setmodelrealbox", "1"};
static void PF_sv_setmodel (void)
{
int i;
const char *m, **check;
@ -311,8 +312,38 @@ static void PF_setmodel (void)
if (mod)
//johnfitz -- correct physics cullboxes for bmodels
/* Spike -- THIS IS A HUGE CLUSTERFUCK.
the mins/maxs sizes of models in vanilla was always set to xyz -16/+16.
which causes issues with clientside culling.
many engines fixed that, but not here.
which means that setmodel-without-setsize is now fucked.
the qc will usually do a setsize after setmodel anyway, so applying that fix here will do nothing.
you'd need to apply the serverside version of the cull fix in SV_LinkEdict instead, which is where the pvs is calculated.
tracebox is limited to specific hull sizes. the traces are biased such that they're aligned to the mins point of the box, rather than the center of the trace.
so vanilla's '-16 -16 -16'/'16 16 16' is wrong for Z (which is usually corrected for with gravity anyway), but X+Y will be correctly aligned for the resulting hull.
but traceboxes using models with -12 or -20 or whatever will be biased/offcenter in the X+Y axis (as well as Z, but that's still mostly unimportant)
deciding whether to replicate the vanilla behaviour based upon model type sucks.
vanilla:
brush - always the models size
mdl - always [-16, -16, -16], [16, 16, 16]
quakespasm:
brush - always the models size
mdl - always the models size
quakeworld:
*.bsp - always the models size (matched by extension rather than type)
other - model isn't even loaded, setmodel does not do setsize at all.
fte default (with nq mod):
*.bsp (or sv_gameplayfix_setmodelrealbox) - always the models size (matched by extension rather than type)
other - always [-16, -16, -16], [16, 16, 16]
fte's behaviour means:
a) dedicated servers don't have to bother loading non-mdls.
b) nq mods still work fine, where extensions are adhered to in the original qc.
c) when replacement models are used for bsp models, things still work without them reverting to +/- 16.
*/
{
if (mod->type == mod_brush)
if (mod->type == mod_brush || !sv_gameplayfix_setmodelrealbox.value)
SetMinMaxSize (e, mod->clipmins, mod->clipmaxs, true);
else
SetMinMaxSize (e, mod->mins, mod->maxs, true);
@ -566,7 +597,7 @@ PF_ambientsound
=================
*/
static void PF_ambientsound (void)
static void PF_sv_ambientsound (void)
{
const char *samp, **check;
float *pos;
@ -716,7 +747,7 @@ static void PF_traceline (void)
if (trace.ent)
pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
else
pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
pr_global_struct->trace_ent = EDICT_TO_PROG(qcvm->edicts);
}
/*
@ -784,10 +815,10 @@ static int PF_newcheckclient (int check)
// 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);
leaf = Mod_PointInLeaf (org, qcvm->worldmodel);
pvs = Mod_LeafPVS (leaf, qcvm->worldmodel);
pvsbytes = (sv.worldmodel->numleafs+7)>>3;
pvsbytes = (qcvm->worldmodel->numleafs+7)>>3;
if (checkpvs == NULL || pvsbytes > checkpvs_capacity)
{
checkpvs_capacity = pvsbytes;
@ -817,7 +848,7 @@ name checkclient ()
*/
#define MAX_CHECK 16
static int c_invis, c_notvis;
static void PF_checkclient (void)
static void PF_sv_checkclient (void)
{
edict_t *ent, *self;
mleaf_t *leaf;
@ -825,29 +856,29 @@ static void PF_checkclient (void)
vec3_t view;
// find a new check if on a new frame
if (sv.time - sv.lastchecktime >= 0.1)
if (qcvm->time - sv.lastchecktime >= 0.1)
{
sv.lastcheck = PF_newcheckclient (sv.lastcheck);
sv.lastchecktime = sv.time;
sv.lastchecktime = qcvm->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_EDICT(qcvm->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;
leaf = Mod_PointInLeaf (view, qcvm->worldmodel);
l = (leaf - qcvm->worldmodel->leafs) - 1;
if ( (l < 0) || !(checkpvs[l>>3] & (1 << (l & 7))) )
{
c_notvis++;
RETURN_EDICT(sv.edicts);
RETURN_EDICT(qcvm->edicts);
return;
}
@ -952,13 +983,13 @@ static void PF_findradius (void)
vec3_t eorg;
int i, j;
chain = (edict_t *)sv.edicts;
chain = (edict_t *)qcvm->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))
ent = NEXT_EDICT(qcvm->edicts);
for (i = 1; i < qcvm->num_edicts; i++, ent = NEXT_EDICT(ent))
{
if (ent->free)
continue;
@ -1048,7 +1079,7 @@ static void PF_Find (void)
if (!s)
PR_RunError ("PF_Find: bad search string");
for (e++ ; e < sv.num_edicts ; e++)
for (e++ ; e < qcvm->num_edicts ; e++)
{
ed = EDICT_NUM(e);
if (ed->free)
@ -1063,7 +1094,7 @@ static void PF_Find (void)
}
}
RETURN_EDICT(sv.edicts);
RETURN_EDICT(qcvm->edicts);
}
static void PR_CheckEmptyString (const char *s)
@ -1106,7 +1137,7 @@ int SV_Precache_Sound(const char *s)
return 0;
}
static void PF_precache_sound (void)
static void PF_sv_precache_sound (void)
{
const char *s;
@ -1143,7 +1174,7 @@ int SV_Precache_Model(const char *s)
return 0;
}
static void PF_precache_model (void)
static void PF_sv_precache_model (void)
{
const char *s;
int i;
@ -1187,12 +1218,12 @@ static void PF_coredump (void)
static void PF_traceon (void)
{
pr_trace = true;
qcvm->trace = true;
}
static void PF_traceoff (void)
{
pr_trace = false;
qcvm->trace = false;
}
static void PF_eprint (void)
@ -1232,14 +1263,14 @@ static void PF_walkmove (void)
move[2] = 0;
// save program state, because SV_movestep may call other progs
oldf = pr_xfunction;
oldf = qcvm->xfunction;
oldself = pr_global_struct->self;
G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
// restore program state
pr_xfunction = oldf;
qcvm->xfunction = oldf;
pr_global_struct->self = oldself;
}
@ -1282,7 +1313,7 @@ PF_lightstyle
void(float style, string value) lightstyle
===============
*/
static void PF_lightstyle (void)
static void PF_sv_lightstyle (void)
{
int style;
const char *val;
@ -1382,9 +1413,9 @@ static void PF_nextent (void)
while (1)
{
i++;
if (i == sv.num_edicts)
if (i == qcvm->num_edicts)
{
RETURN_EDICT(sv.edicts);
RETURN_EDICT(qcvm->edicts);
return;
}
ent = EDICT_NUM(i);
@ -1437,8 +1468,8 @@ static void PF_aim (void)
bestdist = sv_aim.value;
bestent = NULL;
check = NEXT_EDICT(sv.edicts);
for (i = 1; i < sv.num_edicts; i++, check = NEXT_EDICT(check) )
check = NEXT_EDICT(qcvm->edicts);
for (i = 1; i < qcvm->num_edicts; i++, check = NEXT_EDICT(check) )
{
if (check->v.takedamage != DAMAGE_AIM)
continue;
@ -1564,50 +1595,50 @@ sizebuf_t *WriteDest (void)
return NULL;
}
static void PF_WriteByte (void)
static void PF_sv_WriteByte (void)
{
MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
}
static void PF_WriteChar (void)
static void PF_sv_WriteChar (void)
{
MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
}
static void PF_WriteShort (void)
static void PF_sv_WriteShort (void)
{
MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
}
static void PF_WriteLong (void)
static void PF_sv_WriteLong (void)
{
MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
}
static void PF_WriteAngle (void)
static void PF_sv_WriteAngle (void)
{
MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocolflags);
}
static void PF_WriteCoord (void)
static void PF_sv_WriteCoord (void)
{
MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocolflags);
}
static void PF_WriteString (void)
static void PF_sv_WriteString (void)
{
MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
}
#define MSG_WriteEntity MSG_WriteShort //fixme - replacement deltas encodes 0x8000+ in 24 bits
static void PF_WriteEntity (void)
static void PF_sv_WriteEntity (void)
{
MSG_WriteEntity (WriteDest(), G_EDICTNUM(OFS_PARM1));
}
//=============================================================================
static void PF_makestatic (void)
static void PF_sv_makestatic (void)
{
entity_state_t *st;
edict_t *ent;
@ -1642,7 +1673,7 @@ static void PF_makestatic (void)
PF_setspawnparms
==============
*/
static void PF_setspawnparms (void)
static void PF_sv_setspawnparms (void)
{
edict_t *ent;
int i;
@ -1665,7 +1696,7 @@ static void PF_setspawnparms (void)
PF_changelevel
==============
*/
static void PF_changelevel (void)
static void PF_sv_changelevel (void)
{
const char *s;
@ -1696,19 +1727,19 @@ void PR_spawnfunc_misc_model(edict_t *self)
//make sure the model is precached, to avoid errors.
G_INT(OFS_PARM0) = self->v.model;
PF_precache_model();
PF_sv_precache_model();
//and lets just call makestatic instead of worrying if it'll interfere with the rest of the qc.
G_INT(OFS_PARM0) = EDICT_TO_PROG(self);
PF_makestatic();
PF_sv_makestatic();
}
static builtin_t pr_builtin[] =
builtin_t pr_ssqcbuiltins[] =
{
PF_Fixme,
PF_makevectors, // void(entity e) makevectors = #1
PF_setorigin, // void(entity e, vector o) setorigin = #2
PF_setmodel, // void(entity e, string m) setmodel = #3
PF_sv_setmodel, // void(entity e, string m) setmodel = #3
PF_setsize, // void(entity e, vector min, vector max) setsize = #4
PF_Fixme, // void(entity e, vector min, vector max) setabssize = #5
PF_break, // void() break = #6
@ -1722,10 +1753,10 @@ static builtin_t pr_builtin[] =
PF_Spawn, // entity() spawn = #14
PF_Remove, // void(entity e) remove = #15
PF_traceline, // float(vector v1, vector v2, float tryents) traceline = #16
PF_checkclient, // entity() clientlist = #17
PF_sv_checkclient, // entity() clientlist = #17
PF_Find, // entity(entity start, .string fld, string match) find = #18
PF_precache_sound, // void(string s) precache_sound = #19
PF_precache_model, // void(string s) precache_model = #20
PF_sv_precache_sound, // void(string s) precache_sound = #19
PF_sv_precache_model, // void(string s) precache_model = #20
PF_stuffcmd, // void(entity client, string s)stuffcmd = #21
PF_findradius, // entity(vector org, float rad) findradius = #22
PF_bprint, // void(string s) bprint = #23
@ -1740,7 +1771,7 @@ static builtin_t pr_builtin[] =
PF_walkmove, // float(float yaw, float dist) walkmove
PF_Fixme, // float(float yaw, float dist) walkmove
PF_droptofloor,
PF_lightstyle,
PF_sv_lightstyle,
PF_rint,
PF_floor,
PF_ceil,
@ -1758,14 +1789,14 @@ static builtin_t pr_builtin[] =
PF_Fixme,
PF_vectoangles,
PF_WriteByte,
PF_WriteChar,
PF_WriteShort,
PF_WriteLong,
PF_WriteCoord,
PF_WriteAngle,
PF_WriteString,
PF_WriteEntity,
PF_sv_WriteByte,
PF_sv_WriteChar,
PF_sv_WriteShort,
PF_sv_WriteLong,
PF_sv_WriteCoord,
PF_sv_WriteAngle,
PF_sv_WriteString,
PF_sv_WriteEntity,
PF_Fixme,
PF_Fixme,
@ -1777,23 +1808,114 @@ static builtin_t pr_builtin[] =
SV_MoveToGoal,
PF_precache_file,
PF_makestatic,
PF_sv_makestatic,
PF_changelevel,
PF_sv_changelevel,
PF_Fixme,
PF_cvar_set,
PF_centerprint,
PF_ambientsound,
PF_sv_ambientsound,
PF_precache_model,
PF_precache_sound, // precache_sound2 is different only for qcc
PF_sv_precache_model,
PF_sv_precache_sound, // precache_sound2 is different only for qcc
PF_precache_file,
PF_setspawnparms
PF_sv_setspawnparms
};
int pr_ssqcnumbuiltins = sizeof(pr_ssqcbuiltins)/sizeof(pr_ssqcbuiltins[0]);
builtin_t *pr_builtins = pr_builtin;
int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
#define PF_NoCSQC PF_Fixme
#define PF_CSQCToDo PF_Fixme
builtin_t pr_csqcbuiltins[] =
{
PF_Fixme,
PF_makevectors, // void(entity e) makevectors = #1
PF_setorigin, // void(entity e, vector o) setorigin = #2
PF_CSQCToDo,//PF_setmodel, // void(entity e, string m) setmodel = #3
PF_setsize, // void(entity e, vector min, vector max) setsize = #4
PF_Fixme, // void(entity e, vector min, vector max) setabssize = #5
PF_break, // void() break = #6
PF_random, // float() random = #7
PF_sound, // void(entity e, float chan, string samp) sound = #8
PF_normalize, // vector(vector v) normalize = #9
PF_error, // void(string e) error = #10
PF_objerror, // void(string e) objerror = #11
PF_vlen, // float(vector v) vlen = #12
PF_vectoyaw, // float(vector v) vectoyaw = #13
PF_Spawn, // entity() spawn = #14
PF_Remove, // void(entity e) remove = #15
PF_traceline, // float(vector v1, vector v2, float tryents) traceline = #16
PF_NoCSQC, // entity() checkclient (was: clientlist, apparently) = #17
PF_Find, // entity(entity start, .string fld, string match) find = #18
PF_CSQCToDo,//PF_cl_precache_sound, // void(string s) precache_sound = #19
PF_CSQCToDo,//PF_cl_precache_model, // void(string s) precache_model = #20
PF_NoCSQC, // void(entity client, string s)stuffcmd = #21
PF_findradius, // entity(vector org, float rad) findradius = #22
PF_NoCSQC, // void(string s) bprint = #23
PF_NoCSQC, // void(entity client, string s) sprint = #24
PF_dprint, // void(string s) dprint = #25
PF_ftos, // void(string s) ftos = #26
PF_vtos, // void(string s) vtos = #27
PF_coredump,
PF_traceon,
PF_traceoff,
PF_eprint, // void(entity e) debug print an entire entity
PF_walkmove, // float(float yaw, float dist) walkmove
PF_Fixme, // float(float yaw, float dist) walkmove
PF_droptofloor,
PF_CSQCToDo,//PF_cl_lightstyle,
PF_rint,
PF_floor,
PF_ceil,
PF_Fixme,
PF_checkbottom,
PF_pointcontents,
PF_Fixme,
PF_fabs,
PF_NoCSQC,//PF_aim,
PF_cvar,
PF_localcmd,
PF_nextent,
PF_CSQCToDo,//PF_cl_particle,
PF_changeyaw,
PF_Fixme,
PF_vectoangles,
PF_NoCSQC,//PF_WriteByte,
PF_NoCSQC,//PF_WriteChar,
PF_NoCSQC,//PF_WriteShort,
PF_NoCSQC,//PF_WriteLong,
PF_NoCSQC,//PF_WriteCoord,
PF_NoCSQC,//PF_WriteAngle,
PF_NoCSQC,//PF_WriteString,
PF_NoCSQC,//PF_WriteEntity,
PF_Fixme,
PF_Fixme,
PF_Fixme,
PF_Fixme,
PF_Fixme,
PF_Fixme,
PF_Fixme,
SV_MoveToGoal,
PF_precache_file,
PF_CSQCToDo,//PF_cl_makestatic,
PF_NoCSQC,//PF_changelevel,
PF_Fixme,
PF_cvar_set,
PF_NoCSQC,//PF_centerprint,
PF_CSQCToDo,//PF_ambientsound,
PF_CSQCToDo,//PF_cl_precache_model,
PF_CSQCToDo,//PF_cl_precache_sound, // precache_sound2 is different only for qcc
PF_precache_file,
PF_NoCSQC,//PF_setspawnparms
};
int pr_csqcnumbuiltins = sizeof(pr_csqcbuiltins)/sizeof(pr_csqcbuiltins[0]);

View file

@ -23,27 +23,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "quakedef.h"
struct pr_extfields_s pr_extfields;
dprograms_t *progs;
dfunction_t *pr_functions;
static char *pr_strings;
static int pr_stringssize;
static const char **pr_knownstrings;
static int pr_maxknownstrings;
static int pr_numknownstrings;
static int pr_freeknownstrings;
ddef_t *pr_fielddefs;
static ddef_t *pr_globaldefs;
dstatement_t *pr_statements;
globalvars_t *pr_global_struct;
float *pr_globals; // same as pr_global_struct
int pr_edict_size; // in bytes
unsigned short pr_crc;
int type_size[8] = {
1, // ev_void
1, // sizeof(string_t) / 4 // ev_string
@ -79,7 +58,7 @@ Sets everything to NULL
*/
void ED_ClearEdict (edict_t *e)
{
memset (&e->v, 0, progs->entityfields * 4);
memset (&e->v, 0, qcvm->progs->entityfields * 4);
e->free = false;
}
@ -99,24 +78,24 @@ edict_t *ED_Alloc (void)
int i;
edict_t *e;
for (i = svs.maxclients + 1; i < sv.num_edicts; i++)
for (i = qcvm->reserved_edicts; i < qcvm->num_edicts; i++)
{
e = EDICT_NUM(i);
// the first couple seconds of server time can involve a lot of
// freeing and allocating, so relax the replacement policy
if (e->free && ( e->freetime < 2 || sv.time - e->freetime > 0.5 ) )
if (e->free && ( e->freetime < 2 || qcvm->time - e->freetime > 0.5 ) )
{
ED_ClearEdict (e);
return e;
}
}
if (i == sv.max_edicts) //johnfitz -- use sv.max_edicts instead of MAX_EDICTS
Host_Error ("ED_Alloc: no free edicts (max_edicts is %i)", sv.max_edicts);
if (i == qcvm->max_edicts) //johnfitz -- use sv.max_edicts instead of MAX_EDICTS
Host_Error ("ED_Alloc: no free edicts (max_edicts is %i)", qcvm->max_edicts);
sv.num_edicts++;
qcvm->num_edicts++;
e = EDICT_NUM(i);
memset(e, 0, pr_edict_size); // ericw -- switched sv.edicts to malloc(), so we are accessing uninitialized memory and must fully zero it, not just ED_ClearEdict
memset(e, 0, qcvm->edict_size); // ericw -- switched sv.edicts to malloc(), so we are accessing uninitialized memory and must fully zero it, not just ED_ClearEdict
return e;
}
@ -146,7 +125,7 @@ void ED_Free (edict_t *ed)
ed->v.solid = 0;
ed->alpha = ENTALPHA_DEFAULT; //johnfitz -- reset alpha for next entity
ed->freetime = sv.time;
ed->freetime = qcvm->time;
}
//===========================================================================
@ -161,9 +140,9 @@ static ddef_t *ED_GlobalAtOfs (int ofs)
ddef_t *def;
int i;
for (i = 0; i < progs->numglobaldefs; i++)
for (i = 0; i < qcvm->progs->numglobaldefs; i++)
{
def = &pr_globaldefs[i];
def = &qcvm->globaldefs[i];
if (def->ofs == ofs)
return def;
}
@ -180,9 +159,9 @@ static ddef_t *ED_FieldAtOfs (int ofs)
ddef_t *def;
int i;
for (i = 0; i < progs->numfielddefs; i++)
for (i = 0; i < qcvm->progs->numfielddefs; i++)
{
def = &pr_fielddefs[i];
def = &qcvm->fielddefs[i];
if (def->ofs == ofs)
return def;
}
@ -199,9 +178,9 @@ ddef_t *ED_FindField (const char *name)
ddef_t *def;
int i;
for (i = 0; i < progs->numfielddefs; i++)
for (i = 0; i < qcvm->progs->numfielddefs; i++)
{
def = &pr_fielddefs[i];
def = &qcvm->fielddefs[i];
if ( !strcmp(PR_GetString(def->s_name), name) )
return def;
}
@ -228,9 +207,9 @@ ddef_t *ED_FindGlobal (const char *name)
ddef_t *def;
int i;
for (i = 0; i < progs->numglobaldefs; i++)
for (i = 0; i < qcvm->progs->numglobaldefs; i++)
{
def = &pr_globaldefs[i];
def = &qcvm->globaldefs[i];
if ( !strcmp(PR_GetString(def->s_name), name) )
return def;
}
@ -248,9 +227,9 @@ dfunction_t *ED_FindFunction (const char *fn_name)
dfunction_t *func;
int i;
for (i = 0; i < progs->numfunctions; i++)
for (i = 0; i < qcvm->progs->numfunctions; i++)
{
func = &pr_functions[i];
func = &qcvm->functions[i];
if ( !strcmp(PR_GetString(func->s_name), fn_name) )
return func;
}
@ -296,7 +275,7 @@ static const char *PR_ValueString (int type, eval_t *val)
sprintf (line, "entity %i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict)) );
break;
case ev_function:
f = pr_functions + val->function;
f = qcvm->functions + val->function;
sprintf (line, "%s()", PR_GetString(f->s_name));
break;
case ev_field:
@ -352,7 +331,7 @@ const char *PR_UglyValueString (int type, eval_t *val)
q_snprintf (line, sizeof(line), "%i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict)));
break;
case ev_function:
f = pr_functions + val->function;
f = qcvm->functions + val->function;
q_snprintf (line, sizeof(line), "%s", PR_GetString(f->s_name));
break;
case ev_field:
@ -395,7 +374,7 @@ const char *PR_GlobalString (int ofs)
ddef_t *def;
void *val;
val = (void *)&pr_globals[ofs];
val = (void *)&qcvm->globals[ofs];
def = ED_GlobalAtOfs(ofs);
if (!def)
sprintf (line,"%i(?)", ofs);
@ -456,9 +435,9 @@ void ED_Print (edict_t *ed)
}
Con_SafePrintf("\nEDICT %i:\n", NUM_FOR_EDICT(ed)); //johnfitz -- was Con_Printf
for (i = 1; i < progs->numfielddefs; i++)
for (i = 1; i < qcvm->progs->numfielddefs; i++)
{
d = &pr_fielddefs[i];
d = &qcvm->fielddefs[i];
name = PR_GetString(d->s_name);
l = strlen (name);
if (l > 1 && name[l - 2] == '_')
@ -508,9 +487,9 @@ void ED_Write (FILE *f, edict_t *ed)
return;
}
for (i = 1; i < progs->numfielddefs; i++)
for (i = 1; i < qcvm->progs->numfielddefs; i++)
{
d = &pr_fielddefs[i];
d = &qcvm->fielddefs[i];
name = PR_GetString(d->s_name);
j = strlen (name);
if (j > 1 && name[j - 2] == '_')
@ -533,7 +512,7 @@ void ED_Write (FILE *f, edict_t *ed)
}
//johnfitz -- save entity alpha manually when progs.dat doesn't know about alpha
if (pr_extfields.alpha<0 && ed->alpha != ENTALPHA_DEFAULT)
if (qcvm->extfields.alpha<0 && ed->alpha != ENTALPHA_DEFAULT)
fprintf (f, "\"alpha\" \"%f\"\n", ENTALPHA_TOSAVE(ed->alpha));
//johnfitz
@ -559,9 +538,11 @@ void ED_PrintEdicts (void)
if (!sv.active)
return;
Con_Printf ("%i entities\n", sv.num_edicts);
for (i = 0; i < sv.num_edicts; i++)
PR_SwitchQCVM(&sv.qcvm);
Con_Printf ("%i entities\n", qcvm->num_edicts);
for (i = 0; i < qcvm->num_edicts; i++)
ED_PrintNum (i);
PR_SwitchQCVM(NULL);
}
/*
@ -579,12 +560,12 @@ static void ED_PrintEdict_f (void)
return;
i = Q_atoi (Cmd_Argv(1));
if (i < 0 || i >= sv.num_edicts)
{
PR_SwitchQCVM(&sv.qcvm);
if (i < 0 || i >= qcvm->num_edicts)
Con_Printf("Bad edict number\n");
return;
}
ED_PrintNum (i);
else
ED_PrintNum (i);
PR_SwitchQCVM(NULL);
}
/*
@ -602,8 +583,9 @@ static void ED_Count (void)
if (!sv.active)
return;
PR_SwitchQCVM(&sv.qcvm);
active = models = solid = step = 0;
for (i = 0; i < sv.num_edicts; i++)
for (i = 0; i < qcvm->num_edicts; i++)
{
ent = EDICT_NUM(i);
if (ent->free)
@ -617,11 +599,12 @@ static void ED_Count (void)
step++;
}
Con_Printf ("num_edicts:%3i\n", sv.num_edicts);
Con_Printf ("num_edicts:%3i\n", qcvm->num_edicts);
Con_Printf ("active :%3i\n", active);
Con_Printf ("view :%3i\n", models);
Con_Printf ("touch :%3i\n", solid);
Con_Printf ("step :%3i\n", step);
PR_SwitchQCVM(NULL);
}
@ -647,9 +630,9 @@ void ED_WriteGlobals (FILE *f)
int type;
fprintf (f, "{\n");
for (i = 0; i < progs->numglobaldefs; i++)
for (i = 0; i < qcvm->progs->numglobaldefs; i++)
{
def = &pr_globaldefs[i];
def = &qcvm->globaldefs[i];
type = def->type;
if ( !(def->type & DEF_SAVEGLOBAL) )
continue;
@ -660,7 +643,7 @@ void ED_WriteGlobals (FILE *f)
name = PR_GetString(def->s_name);
fprintf (f, "\"%s\" ", name);
fprintf (f, "\"%s\"\n", PR_UglyValueString(type, (eval_t *)&pr_globals[def->ofs]));
fprintf (f, "\"%s\"\n", PR_UglyValueString(type, (eval_t *)&qcvm->globals[def->ofs]));
}
fprintf (f, "}\n");
}
@ -701,7 +684,7 @@ const char *ED_ParseGlobals (const char *data)
continue;
}
if (!ED_ParseEpair ((void *)pr_globals, key, com_token))
if (!ED_ParseEpair ((void *)qcvm->globals, key, com_token))
Host_Error ("ED_ParseGlobals: parse error");
}
return data;
@ -824,7 +807,7 @@ qboolean ED_ParseEpair (void *base, ddef_t *key, const char *s)
Con_Printf ("Can't find function %s\n", s);
return false;
}
*(func_t *)d = func - pr_functions;
*(func_t *)d = func - qcvm->functions;
break;
default:
@ -852,8 +835,8 @@ const char *ED_ParseEdict (const char *data, edict_t *ent)
init = false;
// clear it
if (ent != sv.edicts) // hack
memset (&ent->v, 0, progs->entityfields * 4);
if (ent != qcvm->edicts) // hack
memset (&ent->v, 0, qcvm->progs->entityfields * 4);
// go through all the dictionary pairs
while (1)
@ -938,12 +921,12 @@ const char *ED_ParseEdict (const char *data, edict_t *ent)
eval_t *val;
if (!strcmp(keyname, "traileffect") && sv.state == ss_loading)
{
if ((val = GetEdictFieldValue(ent, pr_extfields.traileffectnum)))
if ((val = GetEdictFieldValue(ent, qcvm->extfields.traileffectnum)))
val->_float = PF_SV_ForceParticlePrecache(com_token);
}
else if (!strcmp(keyname, "emiteffect") && sv.state == ss_loading)
{
if ((val = GetEdictFieldValue(ent, pr_extfields.emiteffectnum)))
if ((val = GetEdictFieldValue(ent, qcvm->extfields.emiteffectnum)))
val->_float = PF_SV_ForceParticlePrecache(com_token);
}
//johnfitz -- HACK -- suppress error becuase fog/sky/alpha fields might not be mentioned in defs.qc
@ -994,7 +977,7 @@ void ED_LoadFromFile (const char *data)
int inhibit = 0;
int usingspawnfunc = 0;
pr_global_struct->time = sv.time;
pr_global_struct->time = qcvm->time;
// parse ents
while (1)
@ -1068,142 +1051,190 @@ void ED_LoadFromFile (const char *data)
}
pr_global_struct->self = EDICT_TO_PROG(ent);
PR_ExecuteProgram (func - pr_functions);
PR_ExecuteProgram (func - qcvm->functions);
}
Con_DPrintf ("%i entities inhibited\n", inhibit);
}
#ifndef PR_SwitchQCVM
qcvm_t *qcvm;
globalvars_t *pr_global_struct;
void PR_SwitchQCVM(qcvm_t *nvm)
{
if (qcvm && nvm)
Sys_Error("PR_SwitchQCVM: A qcvm was already active");
qcvm = nvm;
if (qcvm)
pr_global_struct = (globalvars_t*)qcvm->globals;
else
pr_global_struct = NULL;
}
#endif
void PR_ClearProgs(qcvm_t *vm)
{
qcvm_t *oldvm = qcvm;
if (!vm->progs)
return; //wasn't loaded.
qcvm = NULL;
PR_SwitchQCVM(vm);
PR_ShutdownExtensions();
if (qcvm->knownstrings)
Z_Free ((void *)qcvm->knownstrings);
free(qcvm->edicts); // ericw -- sv.edicts switched to use malloc()
memset(qcvm, 0, sizeof(*qcvm));
qcvm = NULL;
PR_SwitchQCVM(oldvm);
}
/*
===============
PR_LoadProgs
===============
*/
void PR_LoadProgs (void)
qboolean PR_LoadProgs (const char *filename, qboolean fatal, builtin_t *builtins, size_t numbuiltins)
{
int i;
unsigned int u;
PR_ShutdownExtensions();
PR_ClearProgs(qcvm); //just in case.
CRC_Init (&pr_crc);
progs = (dprograms_t *)COM_LoadHunkFile ("progs.dat", NULL);
if (!progs)
Host_Error ("PR_LoadProgs: couldn't load progs.dat");
Con_DPrintf ("Programs occupy %iK.\n", com_filesize/1024);
qcvm->progs = (dprograms_t *)COM_LoadHunkFile (filename, NULL);
if (!qcvm->progs)
return false;
CRC_Init (&qcvm->crc);
for (i = 0; i < com_filesize; i++)
CRC_ProcessByte (&pr_crc, ((byte *)progs)[i]);
CRC_ProcessByte (&qcvm->crc, ((byte *)qcvm->progs)[i]);
// byte swap the header
for (i = 0; i < (int) sizeof(*progs) / 4; i++)
((int *)progs)[i] = LittleLong ( ((int *)progs)[i] );
for (i = 0; i < (int) sizeof(*qcvm->progs) / 4; i++)
((int *)qcvm->progs)[i] = LittleLong ( ((int *)qcvm->progs)[i] );
if (progs->version != PROG_VERSION)
Host_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION);
if (progs->crc != PROGHEADER_CRC)
Host_Error ("progs.dat system vars have been modified, progdefs.h is out of date");
if (qcvm->progs->version != PROG_VERSION)
{
if (fatal)
Host_Error ("%s has wrong version number (%i should be %i)", filename, qcvm->progs->version, PROG_VERSION);
else
{
Con_Printf("%s ABI set not supported", filename);
qcvm->progs = NULL;
return false;
}
}
if (qcvm->progs->crc != PROGHEADER_CRC)
{
if (fatal)
Host_Error ("%s system vars have been modified, progdefs.h is out of date", filename);
else
{
Con_Printf("%s system vars are not supported", filename);
qcvm->progs = NULL;
return false;
}
}
Con_DPrintf ("%s occupies %iK.\n", filename, com_filesize/1024);
pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions);
pr_strings = (char *)progs + progs->ofs_strings;
if (progs->ofs_strings + progs->numstrings >= com_filesize)
Host_Error ("progs.dat strings go past end of file\n");
qcvm->functions = (dfunction_t *)((byte *)qcvm->progs + qcvm->progs->ofs_functions);
qcvm->strings = (char *)qcvm->progs + qcvm->progs->ofs_strings;
if (qcvm->progs->ofs_strings + qcvm->progs->numstrings >= com_filesize)
Host_Error ("%s strings go past end of file\n", filename);
// initialize the strings
pr_numknownstrings = 0;
pr_freeknownstrings = 0;
pr_maxknownstrings = 0;
pr_stringssize = progs->numstrings;
if (pr_knownstrings)
Z_Free ((void *)pr_knownstrings);
pr_knownstrings = NULL;
PR_SetEngineString("");
qcvm->globaldefs = (ddef_t *)((byte *)qcvm->progs + qcvm->progs->ofs_globaldefs);
qcvm->fielddefs = (ddef_t *)((byte *)qcvm->progs + qcvm->progs->ofs_fielddefs);
qcvm->statements = (dstatement_t *)((byte *)qcvm->progs + qcvm->progs->ofs_statements);
pr_globaldefs = (ddef_t *)((byte *)progs + progs->ofs_globaldefs);
pr_fielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs);
pr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements);
qcvm->globals = (float *)((byte *)qcvm->progs + qcvm->progs->ofs_globals);
pr_global_struct = (globalvars_t*)qcvm->globals;
pr_global_struct = (globalvars_t *)((byte *)progs + progs->ofs_globals);
pr_globals = (float *)pr_global_struct;
qcvm->stringssize = qcvm->progs->numstrings;
// byte swap the lumps
for (i = 0; i < progs->numstatements; i++)
for (i = 0; i < qcvm->progs->numstatements; i++)
{
pr_statements[i].op = LittleShort(pr_statements[i].op);
pr_statements[i].a = LittleShort(pr_statements[i].a);
pr_statements[i].b = LittleShort(pr_statements[i].b);
pr_statements[i].c = LittleShort(pr_statements[i].c);
qcvm->statements[i].op = LittleShort(qcvm->statements[i].op);
qcvm->statements[i].a = LittleShort(qcvm->statements[i].a);
qcvm->statements[i].b = LittleShort(qcvm->statements[i].b);
qcvm->statements[i].c = LittleShort(qcvm->statements[i].c);
}
for (i = 0; i < progs->numfunctions; i++)
for (i = 0; i < qcvm->progs->numfunctions; i++)
{
pr_functions[i].first_statement = LittleLong (pr_functions[i].first_statement);
pr_functions[i].parm_start = LittleLong (pr_functions[i].parm_start);
pr_functions[i].s_name = LittleLong (pr_functions[i].s_name);
pr_functions[i].s_file = LittleLong (pr_functions[i].s_file);
pr_functions[i].numparms = LittleLong (pr_functions[i].numparms);
pr_functions[i].locals = LittleLong (pr_functions[i].locals);
qcvm->functions[i].first_statement = LittleLong (qcvm->functions[i].first_statement);
qcvm->functions[i].parm_start = LittleLong (qcvm->functions[i].parm_start);
qcvm->functions[i].s_name = LittleLong (qcvm->functions[i].s_name);
qcvm->functions[i].s_file = LittleLong (qcvm->functions[i].s_file);
qcvm->functions[i].numparms = LittleLong (qcvm->functions[i].numparms);
qcvm->functions[i].locals = LittleLong (qcvm->functions[i].locals);
}
for (i = 0; i < progs->numglobaldefs; i++)
for (i = 0; i < qcvm->progs->numglobaldefs; i++)
{
pr_globaldefs[i].type = LittleShort (pr_globaldefs[i].type);
pr_globaldefs[i].ofs = LittleShort (pr_globaldefs[i].ofs);
pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name);
qcvm->globaldefs[i].type = LittleShort (qcvm->globaldefs[i].type);
qcvm->globaldefs[i].ofs = LittleShort (qcvm->globaldefs[i].ofs);
qcvm->globaldefs[i].s_name = LittleLong (qcvm->globaldefs[i].s_name);
}
for (u = 0; u < sizeof(pr_extfields)/sizeof(int); u++)
((int*)&pr_extfields)[u] = -1;
for (u = 0; u < sizeof(qcvm->extfields)/sizeof(int); u++)
((int*)&qcvm->extfields)[u] = -1;
for (i = 0; i < progs->numfielddefs; i++)
for (i = 0; i < qcvm->progs->numfielddefs; i++)
{
pr_fielddefs[i].type = LittleShort (pr_fielddefs[i].type);
if (pr_fielddefs[i].type & DEF_SAVEGLOBAL)
qcvm->fielddefs[i].type = LittleShort (qcvm->fielddefs[i].type);
if (qcvm->fielddefs[i].type & DEF_SAVEGLOBAL)
Host_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL");
pr_fielddefs[i].ofs = LittleShort (pr_fielddefs[i].ofs);
pr_fielddefs[i].s_name = LittleLong (pr_fielddefs[i].s_name);
qcvm->fielddefs[i].ofs = LittleShort (qcvm->fielddefs[i].ofs);
qcvm->fielddefs[i].s_name = LittleLong (qcvm->fielddefs[i].s_name);
}
for (i = 0; i < progs->numglobals; i++)
((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]);
for (i = 0; i < qcvm->progs->numglobals; i++)
((int *)qcvm->globals)[i] = LittleLong (((int *)qcvm->globals)[i]);
memcpy(qcvm->builtins, builtins, numbuiltins*sizeof(qcvm->builtins[0]));
qcvm->numbuiltins = numbuiltins;
//spike: detect extended fields from progs
pr_extfields.items2 = ED_FindFieldOffset("items2");
pr_extfields.gravity = ED_FindFieldOffset("gravity");
pr_extfields.alpha = ED_FindFieldOffset("alpha");
pr_extfields.movement = ED_FindFieldOffset("movement");
pr_extfields.traileffectnum = ED_FindFieldOffset("traileffectnum");
pr_extfields.emiteffectnum = ED_FindFieldOffset("emiteffectnum");
pr_extfields.viewmodelforclient = ED_FindFieldOffset("viewmodelforclient");
pr_extfields.scale = ED_FindFieldOffset("scale");
pr_extfields.colormod = ED_FindFieldOffset("colormod");
pr_extfields.tag_entity = ED_FindFieldOffset("tag_entity");
pr_extfields.tag_index = ED_FindFieldOffset("tag_index");
pr_extfields.button3 = ED_FindFieldOffset("button3");
pr_extfields.button4 = ED_FindFieldOffset("button4");
pr_extfields.button5 = ED_FindFieldOffset("button5");
pr_extfields.button6 = ED_FindFieldOffset("button6");
pr_extfields.button7 = ED_FindFieldOffset("button7");
pr_extfields.button8 = ED_FindFieldOffset("button8");
pr_extfields.viewzoom = ED_FindFieldOffset("viewzoom");
pr_extfields.modelflags = ED_FindFieldOffset("modelflags");
qcvm->extfields.items2 = ED_FindFieldOffset("items2");
qcvm->extfields.gravity = ED_FindFieldOffset("gravity");
qcvm->extfields.alpha = ED_FindFieldOffset("alpha");
qcvm->extfields.movement = ED_FindFieldOffset("movement");
qcvm->extfields.traileffectnum = ED_FindFieldOffset("traileffectnum");
qcvm->extfields.emiteffectnum = ED_FindFieldOffset("emiteffectnum");
qcvm->extfields.viewmodelforclient = ED_FindFieldOffset("viewmodelforclient");
qcvm->extfields.scale = ED_FindFieldOffset("scale");
qcvm->extfields.colormod = ED_FindFieldOffset("colormod");
qcvm->extfields.tag_entity = ED_FindFieldOffset("tag_entity");
qcvm->extfields.tag_index = ED_FindFieldOffset("tag_index");
qcvm->extfields.button3 = ED_FindFieldOffset("button3");
qcvm->extfields.button4 = ED_FindFieldOffset("button4");
qcvm->extfields.button5 = ED_FindFieldOffset("button5");
qcvm->extfields.button6 = ED_FindFieldOffset("button6");
qcvm->extfields.button7 = ED_FindFieldOffset("button7");
qcvm->extfields.button8 = ED_FindFieldOffset("button8");
qcvm->extfields.viewzoom = ED_FindFieldOffset("viewzoom");
qcvm->extfields.modelflags = ED_FindFieldOffset("modelflags");
i = progs->entityfields;
if (pr_extfields.emiteffectnum < 0)
pr_extfields.emiteffectnum = i++;
if (pr_extfields.traileffectnum < 0)
pr_extfields.traileffectnum = i++;
i = qcvm->progs->entityfields;
if (qcvm->extfields.emiteffectnum < 0)
qcvm->extfields.emiteffectnum = i++;
if (qcvm->extfields.traileffectnum < 0)
qcvm->extfields.traileffectnum = i++;
pr_edict_size = i * 4 + sizeof(edict_t) - sizeof(entvars_t);
qcvm->edict_size = i * 4 + sizeof(edict_t) - sizeof(entvars_t);
// round off to next highest whole word address (esp for Alpha)
// this ensures that pointers in the engine data area are always
// properly aligned
pr_edict_size += sizeof(void *) - 1;
pr_edict_size &= ~(sizeof(void *) - 1);
qcvm->edict_size += sizeof(void *) - 1;
qcvm->edict_size &= ~(sizeof(void *) - 1);
PR_EnableExtensions(pr_globaldefs);
PR_SetEngineString("");
PR_EnableExtensions(qcvm->globaldefs);
return true;
}
@ -1230,24 +1261,26 @@ void PR_Init (void)
Cvar_RegisterVariable (&saved2);
Cvar_RegisterVariable (&saved3);
Cvar_RegisterVariable (&saved4);
PR_InitExtensions();
}
edict_t *EDICT_NUM(int n)
{
if (n < 0 || n >= sv.max_edicts)
if (n < 0 || n >= qcvm->max_edicts)
Host_Error ("EDICT_NUM: bad number %i", n);
return (edict_t *)((byte *)sv.edicts + (n)*pr_edict_size);
return (edict_t *)((byte *)qcvm->edicts + (n)*qcvm->edict_size);
}
int NUM_FOR_EDICT(edict_t *e)
{
int b;
b = (byte *)e - (byte *)sv.edicts;
b = b / pr_edict_size;
b = (byte *)e - (byte *)qcvm->edicts;
b = b / qcvm->edict_size;
if (b < 0 || b >= sv.num_edicts)
if (b < 0 || b >= qcvm->num_edicts)
Host_Error ("NUM_FOR_EDICT: bad pointer");
return b;
}
@ -1259,27 +1292,27 @@ int NUM_FOR_EDICT(edict_t *e)
static void PR_AllocStringSlots (void)
{
pr_maxknownstrings += PR_STRING_ALLOCSLOTS;
Con_DPrintf2("PR_AllocStringSlots: realloc'ing for %d slots\n", pr_maxknownstrings);
pr_knownstrings = (const char **) Z_Realloc ((void *)pr_knownstrings, pr_maxknownstrings * sizeof(char *));
qcvm->maxknownstrings += PR_STRING_ALLOCSLOTS;
Con_DPrintf2("PR_AllocStringSlots: realloc'ing for %d slots\n", qcvm->maxknownstrings);
qcvm->knownstrings = (const char **) Z_Realloc ((void *)qcvm->knownstrings, qcvm->maxknownstrings * sizeof(char *));
}
const char *PR_GetString (int num)
{
if (num >= 0 && num < pr_stringssize)
return pr_strings + num;
else if (num < 0 && num >= -pr_numknownstrings)
if (num >= 0 && num < qcvm->stringssize)
return qcvm->strings + num;
else if (num < 0 && num >= -qcvm->numknownstrings)
{
if (!pr_knownstrings[-1 - num])
if (!qcvm->knownstrings[-1 - num])
{
Host_Error ("PR_GetString: attempt to get a non-existant string %d\n", num);
return "";
}
return pr_knownstrings[-1 - num];
return qcvm->knownstrings[-1 - num];
}
else
{
return pr_strings;
return qcvm->strings;
Host_Error("PR_GetString: invalid string offset %d\n", num);
return "";
}
@ -1287,12 +1320,12 @@ const char *PR_GetString (int num)
void PR_ClearEngineString(int num)
{
if (num < 0 && num >= -pr_numknownstrings)
if (num < 0 && num >= -qcvm->numknownstrings)
{
num = -1 - num;
pr_knownstrings[num] = NULL;
if (pr_freeknownstrings > num)
pr_freeknownstrings = num;
qcvm->knownstrings[num] = NULL;
if (qcvm->freeknownstrings > num)
qcvm->freeknownstrings = num;
}
}
@ -1303,36 +1336,36 @@ int PR_SetEngineString (const char *s)
if (!s)
return 0;
#if 0 /* can't: sv.model_precache & sv.sound_precache points to pr_strings */
if (s >= pr_strings && s <= pr_strings + pr_stringssize)
if (s >= qcvm->strings && s <= qcvm->strings + qcvm->stringssize)
Host_Error("PR_SetEngineString: \"%s\" in pr_strings area\n", s);
#else
if (s >= pr_strings && s <= pr_strings + pr_stringssize - 2)
return (int)(s - pr_strings);
if (s >= qcvm->strings && s <= qcvm->strings + qcvm->stringssize - 2)
return (int)(s - qcvm->strings);
#endif
for (i = 0; i < pr_numknownstrings; i++)
for (i = 0; i < qcvm->numknownstrings; i++)
{
if (pr_knownstrings[i] == s)
if (qcvm->knownstrings[i] == s)
return -1 - i;
}
// new unknown engine string
//Con_DPrintf ("PR_SetEngineString: new engine string %p\n", s);
for (i = pr_freeknownstrings; ; i++)
for (i = qcvm->freeknownstrings; ; i++)
{
if (i < pr_numknownstrings)
if (i < qcvm->numknownstrings)
{
if (pr_knownstrings[i])
if (qcvm->knownstrings[i])
continue;
}
else
{
if (i >= pr_maxknownstrings)
if (i >= qcvm->maxknownstrings)
PR_AllocStringSlots();
pr_numknownstrings++;
qcvm->numknownstrings++;
}
break;
}
pr_freeknownstrings = i+1;
pr_knownstrings[i] = s;
qcvm->freeknownstrings = i+1;
qcvm->knownstrings[i] = s;
return -1 - i;
}
@ -1342,20 +1375,20 @@ int PR_AllocString (int size, char **ptr)
if (!size)
return 0;
for (i = 0; i < pr_numknownstrings; i++)
for (i = 0; i < qcvm->numknownstrings; i++)
{
if (!pr_knownstrings[i])
if (!qcvm->knownstrings[i])
break;
}
// if (i >= pr_numknownstrings)
// {
if (i >= pr_maxknownstrings)
if (i >= qcvm->maxknownstrings)
PR_AllocStringSlots();
pr_numknownstrings++;
qcvm->numknownstrings++;
// }
pr_knownstrings[i] = (char *)Hunk_AllocName(size, "string");
qcvm->knownstrings[i] = (char *)Hunk_AllocName(size, "string");
if (ptr)
*ptr = (char *) pr_knownstrings[i];
*ptr = (char *) qcvm->knownstrings[i];
return -1 - i;
}

View file

@ -21,25 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "quakedef.h"
typedef struct
{
int s;
dfunction_t *f;
} prstack_t;
#define MAX_STACK_DEPTH 64 /* was 32 */
static prstack_t pr_stack[MAX_STACK_DEPTH];
static int pr_depth;
#define LOCALSTACK_SIZE 2048
static int localstack[LOCALSTACK_SIZE];
static int localstack_used;
qboolean pr_trace;
dfunction_t *pr_xfunction;
int pr_xstatement;
int pr_argc;
static const char *pr_opnames[] =
{
"DONE",
@ -185,16 +166,16 @@ static void PR_StackTrace (void)
int i;
dfunction_t *f;
if (pr_depth == 0)
if (qcvm->depth == 0)
{
Con_Printf("<NO STACK>\n");
return;
}
pr_stack[pr_depth].f = pr_xfunction;
for (i = pr_depth; i >= 0; i--)
qcvm->stack[qcvm->depth].f = qcvm->xfunction;
for (i = qcvm->depth; i >= 0; i--)
{
f = pr_stack[i].f;
f = qcvm->stack[i].f;
if (!f)
{
Con_Printf("<NO FUNCTION>\n");
@ -222,14 +203,16 @@ void PR_Profile_f (void)
if (!sv.active)
return;
PR_SwitchQCVM(&sv.qcvm);
num = 0;
do
{
pmax = 0;
best = NULL;
for (i = 0; i < progs->numfunctions; i++)
for (i = 0; i < qcvm->progs->numfunctions; i++)
{
f = &pr_functions[i];
f = &qcvm->functions[i];
if (f->profile > pmax)
{
pmax = f->profile;
@ -244,6 +227,8 @@ void PR_Profile_f (void)
best->profile = 0;
}
} while (best);
PR_SwitchQCVM(NULL);
}
@ -263,12 +248,12 @@ void PR_RunError (const char *error, ...)
q_vsnprintf (string, sizeof(string), error, argptr);
va_end (argptr);
PR_PrintStatement(pr_statements + pr_xstatement);
PR_PrintStatement(qcvm->statements + qcvm->xstatement);
PR_StackTrace();
Con_Printf("%s\n", string);
pr_depth = 0; // dump the stack so host_error can shutdown functions
qcvm->depth = 0; // dump the stack so host_error can shutdown functions
Host_Error("Program error");
}
@ -284,20 +269,20 @@ static int PR_EnterFunction (dfunction_t *f)
{
int i, j, c, o;
pr_stack[pr_depth].s = pr_xstatement;
pr_stack[pr_depth].f = pr_xfunction;
pr_depth++;
if (pr_depth >= MAX_STACK_DEPTH)
qcvm->stack[qcvm->depth].s = qcvm->xstatement;
qcvm->stack[qcvm->depth].f = qcvm->xfunction;
qcvm->depth++;
if (qcvm->depth >= MAX_STACK_DEPTH)
PR_RunError("stack overflow");
// save off any locals that the new function steps on
c = f->locals;
if (localstack_used + c > LOCALSTACK_SIZE)
if (qcvm->localstack_used + c > LOCALSTACK_SIZE)
PR_RunError("PR_ExecuteProgram: locals stack overflow\n");
for (i = 0; i < c ; i++)
localstack[localstack_used + i] = ((int *)pr_globals)[f->parm_start + i];
localstack_used += c;
qcvm->localstack[qcvm->localstack_used + i] = ((int *)qcvm->globals)[f->parm_start + i];
qcvm->localstack_used += c;
// copy parameters
o = f->parm_start;
@ -305,12 +290,12 @@ static int PR_EnterFunction (dfunction_t *f)
{
for (j = 0; j < f->parm_size[i]; j++)
{
((int *)pr_globals)[o] = ((int *)pr_globals)[OFS_PARM0 + i*3 + j];
((int *)qcvm->globals)[o] = ((int *)qcvm->globals)[OFS_PARM0 + i*3 + j];
o++;
}
}
pr_xfunction = f;
qcvm->xfunction = f;
return f->first_statement - 1; // offset the s++
}
@ -323,22 +308,22 @@ static int PR_LeaveFunction (void)
{
int i, c;
if (pr_depth <= 0)
if (qcvm->depth <= 0)
Host_Error("prog stack underflow");
// Restore locals from the stack
c = pr_xfunction->locals;
localstack_used -= c;
if (localstack_used < 0)
c = qcvm->xfunction->locals;
qcvm->localstack_used -= c;
if (qcvm->localstack_used < 0)
PR_RunError("PR_ExecuteProgram: locals stack underflow");
for (i = 0; i < c; i++)
((int *)pr_globals)[pr_xfunction->parm_start + i] = localstack[localstack_used + i];
((int *)qcvm->globals)[qcvm->xfunction->parm_start + i] = qcvm->localstack[qcvm->localstack_used + i];
// up stack
pr_depth--;
pr_xfunction = pr_stack[pr_depth].f;
return pr_stack[pr_depth].s;
qcvm->depth--;
qcvm->xfunction = qcvm->stack[qcvm->depth].f;
return qcvm->stack[qcvm->depth].s;
}
@ -349,9 +334,9 @@ PR_ExecuteProgram
The interpretation main loop
====================
*/
#define OPA ((eval_t *)&pr_globals[(unsigned short)st->a])
#define OPB ((eval_t *)&pr_globals[(unsigned short)st->b])
#define OPC ((eval_t *)&pr_globals[(unsigned short)st->c])
#define OPA ((eval_t *)&qcvm->globals[(unsigned short)st->a])
#define OPB ((eval_t *)&qcvm->globals[(unsigned short)st->b])
#define OPC ((eval_t *)&qcvm->globals[(unsigned short)st->c])
void PR_ExecuteProgram (func_t fnum)
{
@ -362,23 +347,23 @@ void PR_ExecuteProgram (func_t fnum)
edict_t *ed;
int exitdepth;
if (!fnum || fnum >= progs->numfunctions)
if (!fnum || fnum >= qcvm->progs->numfunctions)
{
if (pr_global_struct->self)
ED_Print (PROG_TO_EDICT(pr_global_struct->self));
Host_Error ("PR_ExecuteProgram: NULL function");
}
f = &pr_functions[fnum];
f = &qcvm->functions[fnum];
//FIXME: if this is a builtin, then we're going to crash.
pr_trace = false;
qcvm->trace = false;
// make a stack frame
exitdepth = pr_depth;
exitdepth = qcvm->depth;
st = &pr_statements[PR_EnterFunction(f)];
st = &qcvm->statements[PR_EnterFunction(f)];
startprofile = profile = 0;
while (1)
@ -387,11 +372,11 @@ void PR_ExecuteProgram (func_t fnum)
if (++profile > 10000000) //spike -- was 100000
{
pr_xstatement = st - pr_statements;
qcvm->xstatement = st - qcvm->statements;
PR_RunError("runaway loop error");
}
if (pr_trace)
if (qcvm->trace)
PR_PrintStatement(st);
switch (st->op)
@ -477,7 +462,7 @@ void PR_ExecuteProgram (func_t fnum)
OPC->_float = !OPA->function;
break;
case OP_NOT_ENT:
OPC->_float = (PROG_TO_EDICT(OPA->edict) == sv.edicts);
OPC->_float = (PROG_TO_EDICT(OPA->edict) == qcvm->edicts);
break;
case OP_EQ_F:
@ -534,11 +519,11 @@ void PR_ExecuteProgram (func_t fnum)
case OP_STOREP_FLD: // integers
case OP_STOREP_S:
case OP_STOREP_FNC: // pointers
ptr = (eval_t *)((byte *)sv.edicts + OPB->_int);
ptr = (eval_t *)((byte *)qcvm->edicts + OPB->_int);
ptr->_int = OPA->_int;
break;
case OP_STOREP_V:
ptr = (eval_t *)((byte *)sv.edicts + OPB->_int);
ptr = (eval_t *)((byte *)qcvm->edicts + OPB->_int);
ptr->vector[0] = OPA->vector[0];
ptr->vector[1] = OPA->vector[1];
ptr->vector[2] = OPA->vector[2];
@ -549,12 +534,12 @@ void PR_ExecuteProgram (func_t fnum)
#ifdef PARANOID
NUM_FOR_EDICT(ed); // Make sure it's in range
#endif
if (ed == (edict_t *)sv.edicts && sv.state == ss_active)
if (ed == (edict_t *)qcvm->edicts && sv.state == ss_active)
{
pr_xstatement = st - pr_statements;
qcvm->xstatement = st - qcvm->statements;
PR_RunError("assignment to world entity");
}
OPC->_int = (byte *)((int *)&ed->v + OPB->_int) - (byte *)sv.edicts;
OPC->_int = (byte *)((int *)&ed->v + OPB->_int) - (byte *)qcvm->edicts;
break;
case OP_LOAD_F:
@ -603,35 +588,35 @@ void PR_ExecuteProgram (func_t fnum)
case OP_CALL6:
case OP_CALL7:
case OP_CALL8:
pr_xfunction->profile += profile - startprofile;
qcvm->xfunction->profile += profile - startprofile;
startprofile = profile;
pr_xstatement = st - pr_statements;
pr_argc = st->op - OP_CALL0;
qcvm->xstatement = st - qcvm->statements;
qcvm->argc = st->op - OP_CALL0;
if (!OPA->function)
PR_RunError("NULL function");
newf = &pr_functions[OPA->function];
newf = &qcvm->functions[OPA->function];
if (newf->first_statement < 0)
{ // Built-in function
int i = -newf->first_statement;
if (i >= pr_numbuiltins)
if (i >= qcvm->numbuiltins)
i = 0; //just invoke the fixme builtin.
pr_builtins[i]();
qcvm->builtins[i]();
break;
}
// Normal function
st = &pr_statements[PR_EnterFunction(newf)];
st = &qcvm->statements[PR_EnterFunction(newf)];
break;
case OP_DONE:
case OP_RETURN:
pr_xfunction->profile += profile - startprofile;
qcvm->xfunction->profile += profile - startprofile;
startprofile = profile;
pr_xstatement = st - pr_statements;
pr_globals[OFS_RETURN] = pr_globals[(unsigned short)st->a];
pr_globals[OFS_RETURN + 1] = pr_globals[(unsigned short)st->a + 1];
pr_globals[OFS_RETURN + 2] = pr_globals[(unsigned short)st->a + 2];
st = &pr_statements[PR_LeaveFunction()];
if (pr_depth == exitdepth)
qcvm->xstatement = st - qcvm->statements;
qcvm->globals[OFS_RETURN] = qcvm->globals[(unsigned short)st->a];
qcvm->globals[OFS_RETURN + 1] = qcvm->globals[(unsigned short)st->a + 1];
qcvm->globals[OFS_RETURN + 2] = qcvm->globals[(unsigned short)st->a + 2];
st = &qcvm->statements[PR_LeaveFunction()];
if (qcvm->depth == exitdepth)
{ // Done
return;
}
@ -645,7 +630,7 @@ void PR_ExecuteProgram (func_t fnum)
break;
default:
pr_xstatement = st - pr_statements;
qcvm->xstatement = st - qcvm->statements;
PR_RunError("Bad opcode %i", st->op);
}
} /* end of while(1) loop */

File diff suppressed because it is too large Load diff

View file

@ -59,25 +59,21 @@ typedef struct edict_s
//============================================================================
extern dprograms_t *progs;
extern dfunction_t *pr_functions;
extern dstatement_t *pr_statements;
extern globalvars_t *pr_global_struct;
extern float *pr_globals; /* same as pr_global_struct */
extern ddef_t *pr_fielddefs; //yay reflection.
extern int pr_edict_size; /* in bytes */
typedef void (*builtin_t) (void);
typedef struct qcvm_s qcvm_t;
void PR_Init (void);
void PR_ExecuteProgram (func_t fnum);
void PR_LoadProgs (void);
void PR_ClearProgs(qcvm_t *vm);
qboolean PR_LoadProgs (const char *filename, qboolean fatal, builtin_t *builtins, size_t numbuiltins);
//from pr_ext.c
void PR_InitExtensions(void);
void PR_EnableExtensions(ddef_t *pr_globaldefs); //adds in the extra builtins etc
void PR_AutoCvarChanged(cvar_t *var); //updates the autocvar_ globals when their cvar is changed
void PR_ShutdownExtensions(void); //nooooes!
func_t PR_FindExtFunction(const char *entryname);
void PR_DumpPlatform_f(void); //console command: writes out a qsextensions.qc file
//special hacks...
int PF_SV_ForceParticlePrecache(const char *s);
@ -118,18 +114,20 @@ void ED_LoadFromFile (const char *data);
edict_t *EDICT_NUM(int n);
int NUM_FOR_EDICT(edict_t *e);
#define NEXT_EDICT(e) ((edict_t *)( (byte *)e + pr_edict_size))
#define NEXT_EDICT(e) ((edict_t *)( (byte *)e + qcvm->edict_size))
#define EDICT_TO_PROG(e) ((byte *)e - (byte *)sv.edicts)
#define PROG_TO_EDICT(e) ((edict_t *)((byte *)sv.edicts + e))
#define EDICT_TO_PROG(e) ((byte *)e - (byte *)qcvm->edicts)
#define PROG_TO_EDICT(e) ((edict_t *)((byte *)qcvm->edicts + e))
#define G_FLOAT(o) (pr_globals[o])
#define G_INT(o) (*(int *)&pr_globals[o])
#define G_EDICT(o) ((edict_t *)((byte *)sv.edicts+ *(int *)&pr_globals[o]))
#define G_FLOAT(o) (qcvm->globals[o])
#define G_INT(o) (*(int *)&qcvm->globals[o])
#define G_EDICT(o) ((edict_t *)((byte *)qcvm->edicts+ *(int *)&qcvm->globals[o]))
#define G_EDICTNUM(o) NUM_FOR_EDICT(G_EDICT(o))
#define G_VECTOR(o) (&pr_globals[o])
#define G_STRING(o) (PR_GetString(*(string_t *)&pr_globals[o]))
#define G_FUNCTION(o) (*(func_t *)&pr_globals[o])
#define G_VECTOR(o) (&qcvm->globals[o])
#define G_STRING(o) (PR_GetString(*(string_t *)&qcvm->globals[o]))
#define G_FUNCTION(o) (*(func_t *)&qcvm->globals[o])
#define G_VECTORSET(r,x,y,z) do{G_FLOAT((r)+0) = x; G_FLOAT((r)+1) = y;G_FLOAT((r)+2) = z;}while(0)
#define E_FLOAT(e,o) (((float*)&e->v)[o])
#define E_INT(e,o) (*(int *)&((float*)&e->v)[o])
@ -138,18 +136,6 @@ int NUM_FOR_EDICT(edict_t *e);
extern int type_size[8];
typedef void (*builtin_t) (void);
extern builtin_t *pr_builtins;
extern int pr_numbuiltins;
extern int pr_argc;
extern qboolean pr_trace;
extern dfunction_t *pr_xfunction;
extern int pr_xstatement;
extern unsigned short pr_crc;
FUNC_NORETURN void PR_RunError (const char *error, ...) FUNC_PRINTF(1,2);
#ifdef __WATCOMC__
#pragma aux PR_RunError aborts;
@ -165,19 +151,49 @@ int ED_FindFieldOffset (const char *name);
//from pr_cmds, no longer static so that pr_ext can use them.
sizebuf_t *WriteDest (void);
char *PR_GetTempString (void);
int PR_MakeTempString (const char *val);
char *PF_VarString (int first);
#define STRINGTEMP_BUFFERS 16
#define STRINGTEMP_LENGTH 1024
void PF_Fixme(void); //the 'unimplemented' builtin. woot.
extern struct pr_extfuncs_s
struct pr_extfuncs_s
{ //various global qc entry points that might be called by the engine, if set.
func_t endframe;
func_t parseclientcommand;
} pr_extfuncs;
func_t EndFrame;
func_t SV_ParseClientCommand;
//csqc-specific entry points
func_t CSQC_Init;
func_t CSQC_DrawHud; //for the simple hud-only csqc interface.
func_t CSQC_DrawScores; //(optional) for the simple hud-only csqc interface.
func_t CSQC_InputEvent;
func_t CSQC_ConsoleCommand;
func_t CSQC_Parse_Event;
func_t CSQC_Parse_Damage;
//todo...
// func_t CSQC_Parse_CenterPrint;
// func_t CSQC_Parse_Print;
// func_t CSQC_Parse_TempEntity; //evil... This is the bane of all protocol compatibility. Die.
// func_t CSQC_Parse_StuffCmd; //not in simple. Too easy to make cheats by ignoring server messages.
};
extern cvar_t pr_checkextension; //if 0, extensions are disabled (unless they'd be fatal, but they're still spammy)
extern struct pr_extfields_s
struct pr_extglobals_s
{
//csqc-specific globals...
float *cltime;
float *maxclients;
float *intermission;
float *intermission_time;
float *player_localnum;
float *player_localentnum;
//float *clientcommandframe; //we don't have prediction.
//float *servercommandframe; //we don't have prediction.
};
struct pr_extfields_s
{ //various fields that might be wanted by the engine. -1 == invalid
//I should probably use preprocessor magic for this list or something
int items2; //float
@ -200,7 +216,110 @@ extern struct pr_extfields_s
int viewzoom; //float
int modelflags; //float, the upper 8 bits of .effects
//REMEMBER TO ADD THESE TO qsextensions.qc AND pr_edict.c
} pr_extfields;
};
typedef struct
{
int s;
dfunction_t *f;
} prstack_t;
typedef struct areanode_s
{
int axis; // -1 = leaf node
float dist;
struct areanode_s *children[2];
link_t trigger_edicts;
link_t solid_edicts;
} areanode_t;
#define AREA_DEPTH 4
#define AREA_NODES 32
#define CSIE_KEYDOWN 0
#define CSIE_KEYUP 1
#define CSIE_MOUSEDELTA 2
#define CSIE_MOUSEABS 3
//#define CSIE_ACCELEROMETER 4
//#define CSIE_FOCUS 5
#define CSIE_JOYAXIS 6
//#define CSIE_GYROSCOPE 7
struct qcvm_s
{
dprograms_t *progs;
dfunction_t *functions;
dstatement_t *statements;
float *globals; /* same as pr_global_struct */
ddef_t *fielddefs; //yay reflection.
int edict_size; /* in bytes */
builtin_t builtins[1024];
int numbuiltins;
int argc;
qboolean trace;
dfunction_t *xfunction;
int xstatement;
unsigned short crc;
struct pr_extglobals_s extglobals;
struct pr_extfuncs_s extfuncs;
struct pr_extfields_s extfields;
//was static inside pr_edict
char *strings;
int stringssize;
const char **knownstrings;
int maxknownstrings;
int numknownstrings;
int freeknownstrings;
ddef_t *globaldefs;
unsigned char *knownzone;
size_t knownzonesize;
//originally defined in pr_exec, but moved into the switchable qcvm struct
#define MAX_STACK_DEPTH 64 /* was 32 */
prstack_t stack[MAX_STACK_DEPTH];
int depth;
#define LOCALSTACK_SIZE 2048
int localstack[LOCALSTACK_SIZE];
int localstack_used;
//originally part of the sv_state_t struct
//FIXME: put worldmodel in here too.
double time;
int num_edicts;
int reserved_edicts;
int max_edicts;
edict_t *edicts; // can NOT be array indexed, because edict_t is variable sized, but can be used to reference the world ent
struct qmodel_s *worldmodel;
struct qmodel_s *(*GetModel)(int modelindex); //returns the model for the given index, or null.
//originally from world.c
areanode_t areanodes[AREA_NODES];
int numareanodes;
};
extern globalvars_t *pr_global_struct;
#if 0
extern qcvm_t ssqcvm;
#define qcvm (&ssqcvm)
#define PR_SwitchQCVM(n)
#else
extern qcvm_t *qcvm;
void PR_SwitchQCVM(qcvm_t *nvm);
#endif
extern builtin_t pr_ssqcbuiltins[];
extern int pr_ssqcnumbuiltins;
extern builtin_t pr_csqcbuiltins[];
extern int pr_csqcnumbuiltins;
#endif /* _QUAKE_PROGS_H */

View file

@ -51,6 +51,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// PROTOCOL_FTE_PEXT(1) flags
//mostly uninteresting, mostly superseeded by PEXT2_REPLACEMENTDELTAS...
#define PEXT_CSQC 0x40000000 //csqc additions
// PROTOCOL_FTE_PEXT2 flags
#define PEXT2_PRYDONCURSOR 0x00000001 //a mouse cursor exposed to ssqc
@ -313,6 +314,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define svcfte_spawnbaseline2 66
#define svcfte_updatestatstring 78
#define svcfte_updatestatfloat 79
#define svcfte_cgamepacket 83
#define svcfte_voicechat 84
#define svcfte_setangledelta 85
#define svcfte_updateentities 86
@ -328,6 +330,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define clc_stringcmd 4 // [string] message
#define clcdp_ackframe 50 // [long] frame sequence. reused by fte replacement deltas
#define clcdp_ackdownloaddata 51
#define clcfte_qcrequest 81
#define clcfte_voicechat 83 /*spike*/
//

View file

@ -110,33 +110,38 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// stats are integers communicated to the client by the server
//
#define MAX_CL_STATS 32
#define STAT_HEALTH 0
#define STAT_FRAGS 1
#define STAT_WEAPON 2
#define STAT_AMMO 3
#define STAT_ARMOR 4
#define MAX_CL_STATS 256
#define STAT_HEALTH 0
//#define STAT_FRAGS 1
#define STAT_WEAPON 2
#define STAT_AMMO 3
#define STAT_ARMOR 4
#define STAT_WEAPONFRAME 5
#define STAT_SHELLS 6
#define STAT_NAILS 7
#define STAT_SHELLS 6
#define STAT_NAILS 7
#define STAT_ROCKETS 8
#define STAT_CELLS 9
#define STAT_CELLS 9
#define STAT_ACTIVEWEAPON 10
#define STAT_TOTALSECRETS 11
#define STAT_TOTALMONSTERS 12
#define STAT_SECRETS 13 // bumped on client side by svc_foundsecret
#define STAT_MONSTERS 14 // bumped by svc_killedmonster
#define STAT_ITEMS 15 //replaces clc_clientdata info
#define STAT_VIEWHEIGHT 16 //replaces clc_clientdata info
//#define STAT_TIME 17 //zquake, redundant for nq.
//#define STAT_MATCHSTARTTIME 18
//#define STAT_VIEW2 20
//#define STAT_VIEW2 20
#define STAT_VIEWZOOM 21 // DP
//#define STAT_UNUSED3 22
//#define STAT_UNUSED2 23
//#define STAT_UNUSED1 24
#define STAT_IDEALPITCH 25 //nq-emu
#define STAT_PUNCHANGLE_X 26 //nq-emu
#define STAT_PUNCHANGLE_Y 27 //nq-emu
#define STAT_PUNCHANGLE_Z 28 //nq-emu
#define STAT_PUNCHVECTOR_X 29
#define STAT_PUNCHVECTOR_Y 30
#define STAT_PUNCHVECTOR_Z 31
// stock defines
//

View file

@ -1691,7 +1691,10 @@ skipread:
ptype->t2 = atof(Cmd_Argv(4))/tscale;
ptype->randsmax = atoi(Cmd_Argv(6));
ptype->texsstride = atof(Cmd_Argv(7));
if (Cmd_Argc()>7)
ptype->texsstride = atof(Cmd_Argv(7));/*FIXME: divide-by-tscale missing */
else
ptype->texsstride = 1/tscale;
if (ptype->randsmax < 1 || ptype->texsstride == 0)
ptype->randsmax = 1;

View file

@ -993,6 +993,49 @@ void Sbar_Draw (void)
if (scr_con_current == vid.height)
return; // console is full screen
if (cl.qcvm.extfuncs.CSQC_DrawHud)
{
qboolean deathmatchoverlay = false;
float s = CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0);
sb_updates++;
GL_SetCanvas (CANVAS_CSQC); //johnfitz
glEnable (GL_BLEND); //in the finest tradition of glquake, we litter gl state calls all over the place. yay state trackers.
glDisable (GL_ALPHA_TEST); //in the finest tradition of glquake, we litter gl state calls all over the place. yay state trackers.
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
PR_SwitchQCVM(&cl.qcvm);
if (qcvm->extglobals.cltime)
*qcvm->extglobals.cltime = realtime;
if (qcvm->extglobals.player_localentnum)
*qcvm->extglobals.player_localentnum = cl.viewentity;
pr_global_struct->time = cl.time;
Sbar_SortFrags ();
G_VECTORSET(OFS_PARM0, vid.width/s, vid.height/s, 0);
G_FLOAT(OFS_PARM1) = sb_showscores;
PR_ExecuteProgram(cl.qcvm.extfuncs.CSQC_DrawHud);
if (cl.qcvm.extfuncs.CSQC_DrawScores)
{
G_VECTORSET(OFS_PARM0, vid.width/s, vid.height/s, 0);
G_FLOAT(OFS_PARM1) = sb_showscores;
if (key_dest != key_menu)
PR_ExecuteProgram(cl.qcvm.extfuncs.CSQC_DrawScores);
}
else
deathmatchoverlay = (sb_showscores || cl.stats[STAT_HEALTH] <= 0);
PR_SwitchQCVM(NULL);
glDisable (GL_BLEND);
glEnable (GL_ALPHA_TEST);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //back to ignoring vertex colours.
glDisable(GL_SCISSOR_TEST);
glColor3f (1,1,1);
if (deathmatchoverlay && cl.gametype == GAME_DEATHMATCH)
{
GL_SetCanvas (CANVAS_SBAR);
Sbar_DeathmatchOverlay ();
}
return;
}
if (cl.intermission)
return; //johnfitz -- never draw sbar during intermission
@ -1347,6 +1390,36 @@ void Sbar_IntermissionOverlay (void)
int dig;
int num;
if (cl.qcvm.extfuncs.CSQC_DrawScores)
{
float s = CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0);
GL_SetCanvas (CANVAS_CSQC);
glEnable (GL_BLEND);
glDisable (GL_ALPHA_TEST);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
PR_SwitchQCVM(&cl.qcvm);
if (qcvm->extglobals.cltime)
*qcvm->extglobals.cltime = realtime;
if (qcvm->extglobals.player_localentnum)
*qcvm->extglobals.player_localentnum = cl.viewentity;
if (qcvm->extglobals.intermission)
*qcvm->extglobals.intermission = cl.intermission;
if (qcvm->extglobals.intermission_time)
*qcvm->extglobals.intermission_time = cl.completed_time;
pr_global_struct->time = cl.time;
Sbar_SortFrags ();
G_VECTORSET(OFS_PARM0, vid.width/s, vid.height/s, 0);
G_FLOAT(OFS_PARM1) = sb_showscores;
PR_ExecuteProgram(cl.qcvm.extfuncs.CSQC_DrawScores);
PR_SwitchQCVM(NULL);
glDisable (GL_BLEND);
glEnable (GL_ALPHA_TEST);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glDisable(GL_SCISSOR_TEST);
glColor3f (1,1,1);
return;
}
if (cl.gametype == GAME_DEATHMATCH)
{
Sbar_DeathmatchOverlay ();

View file

@ -68,6 +68,7 @@ typedef enum {
CANVAS_BOTTOMLEFT,
CANVAS_BOTTOMRIGHT,
CANVAS_TOPRIGHT,
CANVAS_CSQC,
CANVAS_INVALID = -1
} canvastype;
extern cvar_t scr_menuscale;

View file

@ -45,23 +45,17 @@ typedef struct
qboolean paused;
qboolean loadgame; // handle connections specially
double time;
int lastcheck; // used by PF_checkclient
double lastchecktime;
qcvm_t qcvm; // Spike: entire qcvm state
char name[64]; // map name
char modelname[64]; // maps/<name>.bsp, for model_precache[0]
struct qmodel_s *worldmodel;
const char *model_precache[MAX_MODELS]; // NULL terminated
struct qmodel_s *models[MAX_MODELS];
const char *sound_precache[MAX_SOUNDS]; // NULL terminated
const char *lightstyles[MAX_LIGHTSTYLES];
int num_edicts;
int max_edicts;
edict_t *edicts; // can NOT be array indexed, because
// edict_t is variable sized, but can
// be used to reference the world ent
server_state_t state; // some actions are only valid during load
sizebuf_t datagram;
@ -94,6 +88,15 @@ typedef struct
} *ambientsounds;
int num_ambients;
int max_ambients;
struct svcustomstat_s
{
int idx;
int type;
int fld;
eval_t *ptr;
} customstats[MAX_CL_STATS*2]; //strings or numeric...
size_t numcustomstats;
} server_t;

View file

@ -36,10 +36,11 @@ unsigned int sv_protocol_pext2; //spike
void SV_CalcStats(client_t *client, int *statsi, float *statsf)
{
size_t i;
edict_t *ent = client->edict;
//FIXME: string stats!
int items;
eval_t *val = GetEdictFieldValue(ent, pr_extfields.items2);
eval_t *val = GetEdictFieldValue(ent, qcvm->extfields.items2);
if (val)
items = (int)ent->v.items | ((int)val->_float << 23);
else
@ -67,7 +68,7 @@ void SV_CalcStats(client_t *client, int *statsi, float *statsf)
// statsi[STAT_TIME] = sv.time*1000; //in ms, this was a hack to work around vanilla QW clients not having any concept of serverside time.
// statsi[STAT_MATCHSTARTTIME] = 0*1000; //in ms, set by the mod to when the current match actually starts (so pregame stuff doesn't interfere with game clocks).
// stats[STAT_VIEW2] = NUM_FOR_EDICT(PROG_TO_EDICT(ent->v.view2));
if ((val = GetEdictFieldValue(ent, pr_extfields.viewzoom)) && val->_float)
if ((val = GetEdictFieldValue(ent, qcvm->extfields.viewzoom)) && val->_float)
{
statsf[STAT_VIEWZOOM] = val->_float*255;
if (statsf[STAT_VIEWZOOM] < 1)
@ -108,6 +109,38 @@ void SV_CalcStats(client_t *client, int *statsi, float *statsf)
// statsf[STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION] = sv_gravity.value;
}
*/
for (i = 0; i < sv.numcustomstats; i++)
{
eval_t *eval = sv.customstats[i].ptr;
if (!eval)
eval = GetEdictFieldValue(ent, sv.customstats[i].fld);
switch(sv.customstats[i].type)
{
case ev_ext_integer:
statsi[sv.customstats[i].idx] = eval->_int;
break;
case ev_entity:
statsi[sv.customstats[i].idx] = NUM_FOR_EDICT(PROG_TO_EDICT(eval->edict));
break;
case ev_float:
statsf[sv.customstats[i].idx] = eval->_float;
break;
case ev_vector:
statsf[sv.customstats[i].idx+0] = eval->vector[0];
statsf[sv.customstats[i].idx+1] = eval->vector[1];
statsf[sv.customstats[i].idx+2] = eval->vector[2];
break;
case ev_string: //not supported in this build... send with svcfte_updatestatstring on change, which is annoying.
case ev_void: //nothing...
case ev_field: //panic! everyone panic!
case ev_function: //doesn't make much sense
case ev_pointer: //doesn't make sense
default:
break;
}
}
}
@ -241,7 +274,18 @@ static unsigned int MSGFTE_DeltaCalcBits(entity_state_t *from, entity_state_t *t
return bits;
}
#define MSG_WriteEntity MSG_WriteShort
//#undef MSG_WriteEntity
void MSG_WriteEntity (sizebuf_t *sb, int c, unsigned int pext2)
{
//high short, low byte
if (c > 0x7fff && (pext2 & PEXT2_REPLACEMENTDELTAS))
{
MSG_WriteShort(sb, 0x8000|(c>>8));
MSG_WriteByte(sb, c&0xff);
}
else
MSG_WriteShort(sb, c);
}
static void MSGFTE_WriteEntityUpdate(unsigned int bits, entity_state_t *state, sizebuf_t *msg, unsigned int pext2, unsigned int protocolflags)
{
unsigned int predbits = 0;
@ -486,7 +530,7 @@ static void MSGFTE_WriteEntityUpdate(unsigned int bits, entity_state_t *state, s
}
*/ if (bits & UF_TAGINFO)
{
MSG_WriteEntity(msg, state->tagentity);
MSG_WriteEntity(msg, state->tagentity, pext2);
MSG_WriteByte(msg, state->tagindex);
}
/* if (bits & UF_LIGHT)
@ -593,7 +637,7 @@ static void SVFTE_SetupFrames(client_t *client)
for (fr = 0; fr < client->numframes; fr++)
client->frames[fr].sequence = client->lastacksequence;
client->numpendingentities = sv.num_edicts;
client->numpendingentities = qcvm->num_edicts;
client->pendingentities_bits = calloc(client->numpendingentities, sizeof(*client->pendingentities_bits));
client->pendingentities_bits[0] = UF_REMOVE;
@ -636,7 +680,7 @@ void SVFTE_Ack(client_t *client, int sequence)
if (frame->sequence >= 0)
{
frame->sequence = -1;
host_client->ping_times[host_client->num_pings%NUM_PING_TIMES] = sv.time - frame->timestamp;
host_client->ping_times[host_client->num_pings%NUM_PING_TIMES] = qcvm->time - frame->timestamp;
host_client->num_pings++;
}
}
@ -706,9 +750,9 @@ static void SVFTE_CalcEntityDeltas(client_t *client)
{
struct entity_num_state_s *olds, *news, *oldstop, *newstop;
if ((int)client->numpendingentities < sv.num_edicts)
if ((int)client->numpendingentities < qcvm->num_edicts)
{
int newmax = sv.num_edicts+64;
int newmax = qcvm->num_edicts+64;
client->pendingentities_bits = realloc(client->pendingentities_bits, sizeof(*client->pendingentities_bits) * newmax);
memset(client->pendingentities_bits+client->numpendingentities, 0, sizeof(*client->pendingentities_bits)*(newmax-client->numpendingentities));
client->numpendingentities = newmax;
@ -780,7 +824,7 @@ static void SVFTE_WriteEntitiesToClient(client_t *client, sizebuf_t *msg, size_t
size_t rollbacksize; //I'm too lazy to figure out sizes (especially if someone updates this for bone states or whatever)
struct deltaframe_s *frame = &client->frames[sequence&(client->numframes-1)];
frame->sequence = sequence; //so we know that it wasn't stale later.
frame->timestamp = sv.time;
frame->timestamp = qcvm->time;
msg->maxsize = overflowsize;
@ -792,7 +836,7 @@ static void SVFTE_WriteEntitiesToClient(client_t *client, sizebuf_t *msg, size_t
frame->numents = 0;
if (client->protocol_pext2 & PEXT2_PREDINFO)
MSG_WriteShort(msg, (client->lastmovemessage&0xffff));
MSG_WriteFloat(msg, sv.time); //should be the time the last physics frame was run.
MSG_WriteFloat(msg, qcvm->time); //should be the time the last physics frame was run.
for (entnum = client->snapshotresume; entnum < client->numpendingentities; entnum++)
{
bits = client->pendingentities_bits[entnum];
@ -892,15 +936,15 @@ void SV_BuildEntityState(edict_t *ent, entity_state_t *state)
state->frame = ent->v.frame;
state->colormap = ent->v.colormap;
state->skin = ent->v.skin;
if ((val = GetEdictFieldValue(ent, pr_extfields.scale)) && val->_float)
if ((val = GetEdictFieldValue(ent, qcvm->extfields.scale)) && val->_float)
state->scale = val->_float*16;
else
state->scale = 16;
if ((val = GetEdictFieldValue(ent, pr_extfields.alpha)))
if ((val = GetEdictFieldValue(ent, qcvm->extfields.alpha)))
state->alpha = ENTALPHA_ENCODE(val->_float);
else
state->alpha = ent->alpha;
if ((val = GetEdictFieldValue(ent, pr_extfields.colormod)) && (val->vector[0]||val->vector[1]||val->vector[2]))
if ((val = GetEdictFieldValue(ent, qcvm->extfields.colormod)) && (val->vector[0]||val->vector[1]||val->vector[2]))
{
state->colormod[0] = val->vector[0]*32;
state->colormod[1] = val->vector[1]*32;
@ -908,18 +952,18 @@ void SV_BuildEntityState(edict_t *ent, entity_state_t *state)
}
else
state->colormod[0] = state->colormod[1] = state->colormod[2] = 32;
state->traileffectnum = GetEdictFieldValue(ent, pr_extfields.traileffectnum)->_float;
state->emiteffectnum = GetEdictFieldValue(ent, pr_extfields.emiteffectnum)->_float;
if ((val = GetEdictFieldValue(ent, pr_extfields.tag_entity)) && val->edict)
state->traileffectnum = GetEdictFieldValue(ent, qcvm->extfields.traileffectnum)->_float;
state->emiteffectnum = GetEdictFieldValue(ent, qcvm->extfields.emiteffectnum)->_float;
if ((val = GetEdictFieldValue(ent, qcvm->extfields.tag_entity)) && val->edict)
state->tagentity = NUM_FOR_EDICT(PROG_TO_EDICT(val->edict));
else
state->tagentity = 0;
if ((val = GetEdictFieldValue(ent, pr_extfields.tag_index)))
if ((val = GetEdictFieldValue(ent, qcvm->extfields.tag_index)))
state->tagindex = val->_float;
else
state->tagindex = 0;
state->effects = ent->v.effects;
if ((val = GetEdictFieldValue(ent, pr_extfields.modelflags)))
if ((val = GetEdictFieldValue(ent, qcvm->extfields.modelflags)))
state->effects |= ((unsigned int)val->_float)<<24;
if (!ent->v.movetype || ent->v.movetype == MOVETYPE_STEP)
state->eflags |= EFLAGS_STEP;
@ -948,24 +992,24 @@ static void SVFTE_BuildSnapshotForClient (client_t *client)
// find the client's PVS
VectorAdd (clent->v.origin, clent->v.view_ofs, org);
pvs = SV_FatPVS (org, sv.worldmodel);
pvs = SV_FatPVS (org, qcvm->worldmodel);
if (maxentities > (unsigned int)sv.num_edicts)
maxentities = (unsigned int)sv.num_edicts;
if (maxentities > (unsigned int)qcvm->num_edicts)
maxentities = (unsigned int)qcvm->num_edicts;
// send over all entities (excpet the client) that touch the pvs
ent = NEXT_EDICT(sv.edicts);
ent = NEXT_EDICT(qcvm->edicts);
for (e=1 ; e<maxentities ; e++, ent = NEXT_EDICT(ent))
{
eflags = 0;
emiteffect = GetEdictFieldValue(ent, pr_extfields.emiteffectnum)->_float;
emiteffect = GetEdictFieldValue(ent, qcvm->extfields.emiteffectnum)->_float;
if (ent != clent) // clent is ALLWAYS sent
{
// ignore ents without visible models
if ((!ent->v.modelindex || !PR_GetString(ent->v.model)[0]) && !emiteffect)
continue;
val = GetEdictFieldValue(ent, pr_extfields.viewmodelforclient);
val = GetEdictFieldValue(ent, qcvm->extfields.viewmodelforclient);
if (val && val->edict == proged)
eflags |= EFLAGS_VIEWMODEL;
else if (val && val->edict)
@ -974,7 +1018,7 @@ static void SVFTE_BuildSnapshotForClient (client_t *client)
{
//attached entities should use the pvs of the parent rather than the child (because the child will typically be bugging out around '0 0 0', so won't be useful)
parent = ent;
while ((val = GetEdictFieldValue(parent, pr_extfields.tag_entity)) && val->edict)
while ((val = GetEdictFieldValue(parent, qcvm->extfields.tag_entity)) && val->edict)
parent = PROG_TO_EDICT(val->edict);
if (parent->num_leafs)
{
@ -1057,7 +1101,7 @@ void MSG_WriteStaticOrBaseLine(sizebuf_t *buf, int idx, entity_state_t *state, u
if (idx>=0)
{
MSG_WriteByte (buf, bits?svcdp_spawnbaseline2:svc_spawnbaseline);
MSG_WriteEntity (buf, idx);
MSG_WriteEntity (buf, idx, protocol_pext2);
}
else
MSG_WriteByte (buf, bits?svcdp_spawnstatic2:svc_spawnstatic);
@ -1076,7 +1120,7 @@ void MSG_WriteStaticOrBaseLine(sizebuf_t *buf, int idx, entity_state_t *state, u
if (idx>=0)
{
MSG_WriteByte (buf, bits?svc_spawnbaseline2:svc_spawnbaseline);
MSG_WriteEntity (buf, idx);
MSG_WriteEntity (buf, idx, protocol_pext2);
}
else
MSG_WriteByte (buf, bits?svc_spawnstatic2:svc_spawnstatic);
@ -1198,6 +1242,7 @@ void SV_Init (void)
extern cvar_t sv_nostep;
extern cvar_t sv_freezenonclients;
extern cvar_t sv_gameplayfix_spawnbeforethinks;
extern cvar_t sv_gameplayfix_setmodelrealbox; //spike: 1 to replicate a quakespasm bug, 0 for actual vanilla compat.
extern cvar_t sv_friction;
extern cvar_t sv_edgefriction;
extern cvar_t sv_stopspeed;
@ -1212,9 +1257,6 @@ void SV_Init (void)
extern cvar_t net_masters[]; //spike
extern cvar_t rcon_password; //spike, proquake-compatible rcon
sv.edicts = NULL; // ericw -- sv.edicts switched to use malloc()
Cvar_RegisterVariable (&sv_maxvelocity);
Cvar_RegisterVariable (&sv_gravity);
Cvar_RegisterVariable (&sv_friction);
@ -1230,6 +1272,7 @@ void SV_Init (void)
Cvar_RegisterVariable (&sv_nostep);
Cvar_RegisterVariable (&sv_freezenonclients);
Cvar_RegisterVariable (&sv_gameplayfix_spawnbeforethinks);
Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
Cvar_RegisterVariable (&pr_checkextension);
Cvar_RegisterVariable (&sv_altnoclip); //johnfitz
@ -1493,7 +1536,7 @@ void SV_SendServerinfo (client_t *client)
{
client->limit_unreliable = DATAGRAM_MTU;//some safe ethernet limit. these clients should accept pretty much anything, but any routers will not.
client->limit_reliable = MAX_DATAGRAM; //quite large, ip allows 16 bits
client->limit_entities = sv.max_edicts; //we don't really know, 8k is probably a save guess but could be 32k, 65k, or even more...
client->limit_entities = qcvm->max_edicts; //we don't really know, 8k is probably a save guess but could be 32k, 65k, or even more...
client->limit_models = MAX_MODELS; //not really sure, client's problem until >14bits
client->limit_sounds = MAX_SOUNDS; //not really sure, client's problem until >14bits
@ -1530,7 +1573,7 @@ void SV_SendServerinfo (client_t *client)
retry:
MSG_WriteByte (&client->message, svc_print);
// sprintf (message, "%c\nFITZQUAKE %1.2f SERVER (%i CRC)\n", 2, FITZQUAKE_VERSION, pr_crc); //johnfitz -- include fitzquake version
sprintf (message, "%c\n"ENGINE_NAME_AND_VER" Server (%i CRC)\n", 2, pr_crc); //spike -- quakespasm has moved on, and has its own server capabilities now. Advertising = good, right?
sprintf (message, "%c\n"ENGINE_NAME_AND_VER" Server (%i CRC)\n", 2, qcvm->crc); //spike -- quakespasm has moved on, and has its own server capabilities now. Advertising = good, right?
MSG_WriteString (&client->message,message);
// lack of serverinfo means any csqc info might as well be sent the lame dp way
@ -1579,7 +1622,7 @@ retry:
else
MSG_WriteByte (&client->message, GAME_COOP);
MSG_WriteString (&client->message, PR_GetString(sv.edicts->v.message));
MSG_WriteString (&client->message, PR_GetString(qcvm->edicts->v.message));
//johnfitz -- only send the first 256 model and sound precaches if protocol is 15
for (i=1,s = sv.model_precache+1 ; *s && i < client->limit_models; s++,i++)
@ -1593,8 +1636,8 @@ retry:
// send music
MSG_WriteByte (&client->message, svc_cdtrack);
MSG_WriteByte (&client->message, sv.edicts->v.sounds);
MSG_WriteByte (&client->message, sv.edicts->v.sounds);
MSG_WriteByte (&client->message, qcvm->edicts->v.sounds);
MSG_WriteByte (&client->message, qcvm->edicts->v.sounds);
// set view
MSG_WriteByte (&client->message, svc_setview);
@ -1630,7 +1673,7 @@ retry:
}
//protocol 15 is too limited. let people know that they'll get a crappy experience.
if (client->limit_entities <= (unsigned)sv.num_edicts)
if (client->limit_entities <= (unsigned)qcvm->num_edicts)
{
Con_Warning("Protocol limitation (entities) for %s\n", NET_QSocketGetTrueAddressString(client->netconnection));
MSG_WriteByte (&client->message, svc_print);
@ -1933,7 +1976,7 @@ SV_WriteEntitiesToClient
void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg)
{
edict_t *clent = client->edict;
unsigned int e, i, maxedict=sv.num_edicts;
unsigned int e, i, maxedict=qcvm->num_edicts;
int bits;
byte *pvs;
vec3_t org;
@ -1951,10 +1994,10 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg)
// find the client's PVS
VectorAdd (clent->v.origin, clent->v.view_ofs, org);
pvs = SV_FatPVS (org, sv.worldmodel);
pvs = SV_FatPVS (org, qcvm->worldmodel);
// send over all entities (excpet the client) that touch the pvs
ent = NEXT_EDICT(sv.edicts);
ent = NEXT_EDICT(qcvm->edicts);
for (e=1 ; e<maxedict ; e++, ent = NEXT_EDICT(ent))
{
@ -2036,7 +2079,7 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg)
//johnfitz -- alpha
// TODO: find a cleaner place to put this code
val = GetEdictFieldValue(ent, pr_extfields.alpha);
val = GetEdictFieldValue(ent, qcvm->extfields.alpha);
if (val)
ent->alpha = ENTALPHA_ENCODE(val->_float);
@ -2151,7 +2194,7 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg)
if (bits & U_MODEL2)
MSG_WriteByte(msg, (int)ent->v.modelindex >> 8);
if (bits & U_LERPFINISH)
MSG_WriteByte(msg, (byte)(Q_rint((ent->v.nextthink-sv.time)*255)));
MSG_WriteByte(msg, (byte)(Q_rint((ent->v.nextthink-qcvm->time)*255)));
//johnfitz
}
}
@ -2176,8 +2219,8 @@ void SV_CleanupEnts (void)
int e;
edict_t *ent;
ent = NEXT_EDICT(sv.edicts);
for (e=1 ; e<sv.num_edicts ; e++, ent = NEXT_EDICT(ent))
ent = NEXT_EDICT(qcvm->edicts);
for (e=1 ; e<qcvm->num_edicts ; e++, ent = NEXT_EDICT(ent))
{
ent->v.effects = (int)ent->v.effects & ~EF_MUZZLEFLASH;
}
@ -2253,7 +2296,7 @@ void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
// stuff the sigil bits into the high bits of items for sbar, or else
// mix in items2
val = GetEdictFieldValue(ent, pr_extfields.items2);
val = GetEdictFieldValue(ent, qcvm->extfields.items2);
if (val)
items = (int)ent->v.items | ((int)val->_float << 23);
@ -2442,7 +2485,7 @@ qboolean SV_SendClientDatagram (client_t *client)
else
{
MSG_WriteByte (&msg, svc_time);
MSG_WriteFloat (&msg, sv.time);
MSG_WriteFloat (&msg, qcvm->time);
if (client->protocol_pext2 & PEXT2_PREDINFO)
MSG_WriteShort(&msg, (client->lastmovemessage&0xffff));
@ -2626,7 +2669,7 @@ int SV_SendPrespawnBaselines(int idx)
while (1)
{
if (idx >= sv.num_edicts)
if (idx >= qcvm->num_edicts)
return -1;
svent = EDICT_NUM(idx);
@ -2801,7 +2844,7 @@ void SV_CreateBaseline (void)
int entnum;
eval_t *val;
for (entnum = 0; entnum < sv.num_edicts; entnum++)
for (entnum = 0; entnum < qcvm->num_edicts; entnum++)
{
// get the current server version
svent = EDICT_NUM(entnum);
@ -2827,7 +2870,7 @@ void SV_CreateBaseline (void)
{
svent->baseline.colormap = 0;
svent->baseline.modelindex = SV_ModelIndex(PR_GetString(svent->v.model));
val = GetEdictFieldValue(svent, pr_extfields.alpha);
val = GetEdictFieldValue(svent, qcvm->extfields.alpha);
if (val)
svent->baseline.alpha = ENTALPHA_ENCODE(val->_float);
else
@ -2923,7 +2966,9 @@ void SV_SpawnServer (const char *server)
//
if (sv.active)
{
PR_SwitchQCVM(NULL);
SV_SendReconnect ();
PR_SwitchQCVM(&sv.qcvm);
}
//
@ -2958,12 +3003,12 @@ void SV_SpawnServer (const char *server)
else sv.protocolflags = 0;
// load progs to get entity field count
PR_LoadProgs ();
PR_LoadProgs ("progs.dat", true, pr_ssqcbuiltins, pr_ssqcnumbuiltins);
// allocate server memory
/* Host_ClearMemory() called above already cleared the whole sv structure */
sv.max_edicts = CLAMP (MIN_EDICTS,(int)max_edicts.value,MAX_EDICTS); //johnfitz -- max_edicts cvar
sv.edicts = (edict_t *) malloc (sv.max_edicts*pr_edict_size); // ericw -- sv.edicts switched to use malloc()
qcvm->max_edicts = CLAMP (MIN_EDICTS,(int)max_edicts.value,MAX_EDICTS); //johnfitz -- max_edicts cvar
qcvm->edicts = (edict_t *) malloc (qcvm->max_edicts*qcvm->edict_size); // ericw -- sv.edicts switched to use malloc()
sv.datagram.maxsize = sizeof(sv.datagram_buf);
sv.datagram.cursize = 0;
@ -2982,8 +3027,8 @@ void SV_SpawnServer (const char *server)
sv.signon.data = sv.signon_buf;
// leave slots at start for clients only
sv.num_edicts = svs.maxclients+1;
memset(sv.edicts, 0, sv.num_edicts*pr_edict_size); // ericw -- sv.edicts switched to use malloc()
qcvm->num_edicts = qcvm->reserved_edicts = svs.maxclients+1;
memset(qcvm->edicts, 0, qcvm->num_edicts*qcvm->edict_size); // ericw -- sv.edicts switched to use malloc()
for (i=0 ; i<svs.maxclients ; i++)
{
ent = EDICT_NUM(i+1);
@ -2993,18 +3038,18 @@ void SV_SpawnServer (const char *server)
sv.state = ss_loading;
sv.paused = false;
sv.time = 1.0;
qcvm->time = 1.0;
q_strlcpy (sv.name, server, sizeof(sv.name));
q_snprintf (sv.modelname, sizeof(sv.modelname), "maps/%s.bsp", server);
sv.worldmodel = Mod_ForName (sv.modelname, false);
if (!sv.worldmodel || sv.worldmodel->type != mod_brush)
qcvm->worldmodel = Mod_ForName (sv.modelname, false);
if (!qcvm->worldmodel || qcvm->worldmodel->type != mod_brush)
{
Con_Printf ("Couldn't spawn server %s\n", sv.modelname);
sv.active = false;
return;
}
sv.models[1] = sv.worldmodel;
sv.models[1] = qcvm->worldmodel;
//
// clear world interaction links
@ -3014,13 +3059,13 @@ void SV_SpawnServer (const char *server)
sv.sound_precache[0] = dummy;
sv.model_precache[0] = dummy;
sv.model_precache[1] = sv.modelname;
if (sv.worldmodel->numsubmodels > MAX_MODELS)
if (qcvm->worldmodel->numsubmodels > MAX_MODELS)
{
Con_Printf ("too many inline models %s\n", sv.modelname);
sv.active = false;
return;
}
for (i=1 ; i<sv.worldmodel->numsubmodels ; i++)
for (i=1 ; i<qcvm->worldmodel->numsubmodels ; i++)
{
sv.model_precache[1+i] = localmodels[i];
sv.models[i+1] = Mod_ForName (localmodels[i], false);
@ -3030,9 +3075,9 @@ void SV_SpawnServer (const char *server)
// load the rest of the entities
//
ent = EDICT_NUM(0);
memset (&ent->v, 0, progs->entityfields * 4);
memset (&ent->v, 0, qcvm->progs->entityfields * 4);
ent->free = false;
ent->v.model = PR_SetEngineString(sv.worldmodel->name);
ent->v.model = PR_SetEngineString(qcvm->worldmodel->name);
ent->v.modelindex = 1; // world model
ent->v.solid = SOLID_BSP;
ent->v.movetype = MOVETYPE_PUSH;
@ -3047,7 +3092,7 @@ void SV_SpawnServer (const char *server)
// serverflags are for cross level information (sigils)
pr_global_struct->serverflags = svs.serverflags;
ED_LoadFromFile (sv.worldmodel->entities);
ED_LoadFromFile (qcvm->worldmodel->entities);
sv.active = true;
@ -3069,8 +3114,11 @@ void SV_SpawnServer (const char *server)
// send serverinfo to all connected clients
for (i=0,host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
{
host_client->knowntoqc = false;
if (host_client->active)
SV_SendServerinfo (host_client);
}
Con_DPrintf ("Server spawned.\n");
}

View file

@ -129,7 +129,7 @@ qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
{
VectorAdd (ent->v.origin, move, neworg);
enemy = PROG_TO_EDICT(ent->v.enemy);
if (i == 0 && enemy != sv.edicts)
if (i == 0 && enemy != qcvm->edicts)
{
dz = ent->v.origin[2] - PROG_TO_EDICT(ent->v.enemy)->v.origin[2];
if (dz > 40)
@ -150,7 +150,7 @@ qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
return true;
}
if (enemy == sv.edicts)
if (enemy == qcvm->edicts)
break;
}
@ -408,7 +408,7 @@ void SV_MoveToGoal (void)
}
// if the next step hits the enemy, return immediately
if ( PROG_TO_EDICT(ent->v.enemy) != sv.edicts && SV_CloseEnough (ent, goal, dist) )
if ( PROG_TO_EDICT(ent->v.enemy) != qcvm->edicts && SV_CloseEnough (ent, goal, dist) )
return;
// bump around...

View file

@ -65,8 +65,8 @@ void SV_CheckAllEnts (void)
edict_t *check;
// see if any solid entities are inside the final position
check = NEXT_EDICT(sv.edicts);
for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
check = NEXT_EDICT(qcvm->edicts);
for (e=1 ; e<qcvm->num_edicts ; e++, check = NEXT_EDICT(check))
{
if (check->free)
continue;
@ -128,11 +128,11 @@ qboolean SV_RunThink (edict_t *ent)
int i; //johnfitz
thinktime = ent->v.nextthink;
if (thinktime <= 0 || thinktime > sv.time + host_frametime)
if (thinktime <= 0 || thinktime > qcvm->time + host_frametime)
return true;
if (thinktime < sv.time)
thinktime = sv.time; // don't let things stay in the past.
if (thinktime < qcvm->time)
thinktime = qcvm->time; // don't let things stay in the past.
// it is possible to start that way
// by a trigger with a local time.
@ -141,7 +141,7 @@ qboolean SV_RunThink (edict_t *ent)
ent->v.nextthink = 0;
pr_global_struct->time = thinktime;
pr_global_struct->self = EDICT_TO_PROG(ent);
pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
pr_global_struct->other = EDICT_TO_PROG(qcvm->edicts);
PR_ExecuteProgram (ent->v.think);
//johnfitz -- PROTOCOL_FITZQUAKE
@ -173,7 +173,7 @@ void SV_Impact (edict_t *e1, edict_t *e2)
old_self = pr_global_struct->self;
old_other = pr_global_struct->other;
pr_global_struct->time = sv.time;
pr_global_struct->time = qcvm->time;
if (e1->v.touch && e1->v.solid != SOLID_NOT)
{
pr_global_struct->self = EDICT_TO_PROG(e1);
@ -389,7 +389,7 @@ void SV_AddGravity (edict_t *ent)
float ent_gravity;
eval_t *val;
val = GetEdictFieldValue(ent, pr_extfields.gravity);
val = GetEdictFieldValue(ent, qcvm->extfields.gravity);
if (val && val->_float)
ent_gravity = val->_float;
else
@ -479,14 +479,14 @@ void SV_PushMove (edict_t *pusher, float movetime)
//johnfitz -- dynamically allocate
mark = Hunk_LowMark ();
moved_edict = (edict_t **) Hunk_Alloc (sv.num_edicts*sizeof(edict_t *));
moved_from = (vec3_t *) Hunk_Alloc (sv.num_edicts*sizeof(vec3_t));
moved_edict = (edict_t **) Hunk_Alloc (qcvm->num_edicts*sizeof(edict_t *));
moved_from = (vec3_t *) Hunk_Alloc (qcvm->num_edicts*sizeof(vec3_t));
//johnfitz
// see if any solid entities are inside the final position
num_moved = 0;
check = NEXT_EDICT(sv.edicts);
for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
check = NEXT_EDICT(qcvm->edicts);
for (e=1 ; e<qcvm->num_edicts ; e++, check = NEXT_EDICT(check))
{
if (check->free)
continue;
@ -612,9 +612,9 @@ void SV_Physics_Pusher (edict_t *ent)
if (thinktime > oldltime && thinktime <= ent->v.ltime)
{
ent->v.nextthink = 0;
pr_global_struct->time = sv.time;
pr_global_struct->time = qcvm->time;
pr_global_struct->self = EDICT_TO_PROG(ent);
pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
pr_global_struct->other = EDICT_TO_PROG(qcvm->edicts);
PR_ExecuteProgram (ent->v.think);
if (ent->free)
return;
@ -925,7 +925,7 @@ void SV_Physics_Client (edict_t *ent, int num)
//
// call standard client pre-think
//
pr_global_struct->time = sv.time;
pr_global_struct->time = qcvm->time;
pr_global_struct->self = EDICT_TO_PROG(ent);
PR_ExecuteProgram (pr_global_struct->PlayerPreThink);
@ -979,7 +979,7 @@ void SV_Physics_Client (edict_t *ent, int num)
//
SV_LinkEdict (ent, true);
pr_global_struct->time = sv.time;
pr_global_struct->time = qcvm->time;
pr_global_struct->self = EDICT_TO_PROG(ent);
PR_ExecuteProgram (pr_global_struct->PlayerPostThink);
}
@ -1241,9 +1241,9 @@ void SV_Physics (void)
edict_t *ent;
// let the progs know that a new frame has started
pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
pr_global_struct->time = sv.time;
pr_global_struct->self = EDICT_TO_PROG(qcvm->edicts);
pr_global_struct->other = EDICT_TO_PROG(qcvm->edicts);
pr_global_struct->time = qcvm->time;
PR_ExecuteProgram (pr_global_struct->StartFrame);
//SV_CheckAllEnts ();
@ -1251,12 +1251,12 @@ void SV_Physics (void)
//
// treat each object in turn
//
ent = sv.edicts;
ent = qcvm->edicts;
if (sv_freezenonclients.value)
entity_cap = svs.maxclients + 1; // Only run physics on clients and the world
else
entity_cap = sv.num_edicts;
entity_cap = qcvm->num_edicts;
//for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
for (i=0 ; i<entity_cap ; i++, ent = NEXT_EDICT(ent))
@ -1304,14 +1304,14 @@ void SV_Physics (void)
pr_global_struct->force_retouch--;
if (pr_extfuncs.endframe)
if (qcvm->extfuncs.EndFrame)
{
pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
pr_global_struct->time = sv.time;
PR_ExecuteProgram (pr_extfuncs.endframe);
pr_global_struct->self = EDICT_TO_PROG(qcvm->edicts);
pr_global_struct->other = EDICT_TO_PROG(qcvm->edicts);
pr_global_struct->time = qcvm->time;
PR_ExecuteProgram (qcvm->extfuncs.EndFrame);
}
if (!sv_freezenonclients.value)
sv.time += host_frametime;
qcvm->time += host_frametime;
}

View file

@ -284,7 +284,7 @@ void SV_WaterMove (void)
void SV_WaterJump (void)
{
if (sv.time > sv_player->v.teleport_time
if (qcvm->time > sv_player->v.teleport_time
|| !sv_player->v.waterlevel)
{
sv_player->v.flags = (int)sv_player->v.flags & ~FL_WATERJUMP;
@ -335,7 +335,7 @@ void SV_AirMove (void)
smove = cmd.sidemove;
// hack to not let you back into teleporter
if (sv.time < sv_player->v.teleport_time && fmove < 0)
if (qcvm->time < sv_player->v.teleport_time && fmove < 0)
fmove = 0;
for (i=0 ; i<3 ; i++)
@ -486,7 +486,7 @@ void SV_ReadClientMove (usercmd_t *move)
if (!(host_client->protocol_pext2 & PEXT2_PREDINFO))
{
host_client->ping_times[host_client->num_pings%NUM_PING_TIMES]
= sv.time - timestamp;
= qcvm->time - timestamp;
host_client->num_pings++;
} //otherwise time is still useful for determining the input frame's time value
@ -500,23 +500,23 @@ void SV_ReadClientMove (usercmd_t *move)
host_client->edict->v.button0 = (buttonbits & 1)>>0;
//button1 was meant to be 'use', but got reused by too many mods to get implemented now
host_client->edict->v.button2 = (buttonbits & 2)>>1;
if ((val = GetEdictFieldValue(host_client->edict, pr_extfields.button3)))
if ((val = GetEdictFieldValue(host_client->edict, qcvm->extfields.button3)))
val->_float = (buttonbits & 4)>>2;
if ((val = GetEdictFieldValue(host_client->edict, pr_extfields.button4)))
if ((val = GetEdictFieldValue(host_client->edict, qcvm->extfields.button4)))
val->_float = (buttonbits & 8)>>3;
if ((val = GetEdictFieldValue(host_client->edict, pr_extfields.button5)))
if ((val = GetEdictFieldValue(host_client->edict, qcvm->extfields.button5)))
val->_float = (buttonbits & 0x10)>>4;
if ((val = GetEdictFieldValue(host_client->edict, pr_extfields.button6)))
if ((val = GetEdictFieldValue(host_client->edict, qcvm->extfields.button6)))
val->_float = (buttonbits & 0x20)>>5;
if ((val = GetEdictFieldValue(host_client->edict, pr_extfields.button7)))
if ((val = GetEdictFieldValue(host_client->edict, qcvm->extfields.button7)))
val->_float = (buttonbits & 0x40)>>6;
if ((val = GetEdictFieldValue(host_client->edict, pr_extfields.button8)))
if ((val = GetEdictFieldValue(host_client->edict, qcvm->extfields.button8)))
val->_float = (buttonbits & 0x80)>>7;
if (newimpulse)
host_client->edict->v.impulse = newimpulse;
eval = GetEdictFieldValue(host_client->edict, pr_extfields.movement);
eval = GetEdictFieldValue(host_client->edict, qcvm->extfields.movement);
if (eval)
{
eval->vector[0] = move->forwardmove;
@ -527,6 +527,98 @@ void SV_ReadClientMove (usercmd_t *move)
//FIXME: attempt to apply physics command now, if the mod has custom physics+csqc-prediction
}
void SV_ReadQCRequest(void)
{
int e;
char args[8];
const char *rname, *fname;
func_t f;
int i;
client_t *cl = host_client;
for (i = 0; ; )
{
byte ev = MSG_ReadByte();
/*if (ev >= 200 && ev < 200+MAX_SPLITS)
{
ev -= 200;
while (ev-- && cl)
cl = cl->controlled;
continue;
}*/
if (i >= sizeof(args)-1)
{
if (ev != ev_void)
{
msg_badread = true;
return;
}
goto done;
}
switch(ev)
{
default:
args[i] = '?';
G_INT(OFS_PARM0+i*3) = MSG_ReadLong();
break;
case ev_void:
goto done;
case ev_float:
args[i] = 'f';
G_FLOAT(OFS_PARM0+i*3) = MSG_ReadFloat();
break;
case ev_vector:
args[i] = 'v';
G_FLOAT(OFS_PARM0+i*3+0) = MSG_ReadFloat();
G_FLOAT(OFS_PARM0+i*3+1) = MSG_ReadFloat();
G_FLOAT(OFS_PARM0+i*3+2) = MSG_ReadFloat();
break;
case ev_ext_integer:
args[i] = 'i';
G_INT(OFS_PARM0+i*3) = MSG_ReadLong();
break;
case ev_string:
args[i] = 's';
G_INT(OFS_PARM0+i*3) = PR_MakeTempString(MSG_ReadString());
break;
case ev_entity:
args[i] = 'e';
e = MSG_ReadEntity(host_client->protocol_pext2);
if (e < 0 || e >= qcvm->num_edicts)
e = 0;
G_INT(OFS_PARM0+i*3) = EDICT_TO_PROG(EDICT_NUM(e));
break;
}
i++;
}
done:
args[i] = 0;
rname = MSG_ReadString();
if (i)
fname = va("CSEv_%s_%s", rname, args);
else
fname = va("CSEv_%s", rname);
f = PR_FindExtFunction(fname);
/*if (!f)
{
if (i)
rname = va("Cmd_%s_%s", rname, args);
else
rname = va("Cmd_%s", rname);
f = PR_FindExtFunction(rname);
}*/
if (!cl)
; //bad seat! not going to warn as they might have been removed recently
else if (f)
{
pr_global_struct->self = EDICT_TO_PROG(cl->edict);
PR_ExecuteProgram(f);
}
else
SV_ClientPrintf("qcrequest \"%s\" not supported\n", fname);
}
/*
===================
SV_ReadClientMessage
@ -569,14 +661,14 @@ qboolean SV_ReadClientMessage (void)
case clc_stringcmd:
s = MSG_ReadString ();
if (q_strncasecmp(s, "spawn", 5) && q_strncasecmp(s, "begin", 5) && q_strncasecmp(s, "prespawn", 8) && pr_extfuncs.parseclientcommand)
if (q_strncasecmp(s, "spawn", 5) && q_strncasecmp(s, "begin", 5) && q_strncasecmp(s, "prespawn", 8) && qcvm->extfuncs.SV_ParseClientCommand)
{ //the spawn/begin/prespawn are because of numerous mods that disobey the rules.
//at a minimum, we must be able to join the server, so that we can see any sprints/bprints (because dprint sucks, yes there's proper ways to deal with this, but moders don't always know them).
client_t *ohc = host_client;
G_INT(OFS_PARM0) = PR_SetEngineString(s);
pr_global_struct->time = sv.time;
pr_global_struct->time = qcvm->time;
pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
PR_ExecuteProgram(pr_extfuncs.parseclientcommand);
PR_ExecuteProgram(qcvm->extfuncs.SV_ParseClientCommand);
host_client = ohc;
}
else
@ -601,6 +693,10 @@ qboolean SV_ReadClientMessage (void)
Host_DownloadAck(host_client);
break;
case clcfte_qcrequest:
SV_ReadQCRequest();
break;
case clcfte_voicechat:
SV_VoiceReadPacket(host_client);
break;
@ -664,7 +760,7 @@ void SV_RunClients (void)
//botclients can't receive packets. don't even try.
//not sure where to put this code, but here seems sane enough.
//fill in the user's desired stuff according to a few things.
eval_t *ev = GetEdictFieldValue(host_client->edict, pr_extfields.movement);
eval_t *ev = GetEdictFieldValue(host_client->edict, qcvm->extfields.movement);
if (ev) //.movement normally works the other way around. oh well.
{
host_client->cmd.forwardmove = ev->vector[0];

View file

@ -391,6 +391,7 @@ void Sys_Error (const char *error, ...)
fputs (errortxt1, stderr);
Con_Redirect(NULL);
PR_SwitchQCVM(NULL);
Host_Shutdown ();
fputs (errortxt2, stderr);
fputs (text, stderr);

View file

@ -312,6 +312,8 @@ void Sys_Error (const char *error, ...)
q_vsnprintf (text, sizeof(text), error, argptr);
va_end (argptr);
PR_SwitchQCVM(NULL);
Con_Redirect(NULL);
if (isDedicated)
@ -377,7 +379,11 @@ void Sys_Quit (void)
double Sys_DoubleTime (void)
{
#if 1
return SDL_GetPerformanceCounter() / (long double)SDL_GetPerformanceFrequency();
#else
return SDL_GetTicks() / 1000.0;
#endif
}
const char *Sys_ConsoleInput (void)

View file

@ -88,6 +88,7 @@ void *VID_GetWindow (void);
qboolean VID_HasMouseOrInputFocus (void);
qboolean VID_IsMinimized (void);
void VID_Lock (void);
void VID_SetWindowCaption(const char *newcaption);
#endif /* __VID_DEFS_H */

View file

@ -279,6 +279,21 @@ void V_ParseDamage (void)
for (i=0 ; i<3 ; i++)
from[i] = MSG_ReadCoord (cl.protocolflags);
if (cl.qcvm.extfuncs.CSQC_Parse_Damage)
{
qboolean inhibit;
PR_SwitchQCVM(&cl.qcvm);
pr_global_struct->time = cl.time;
G_FLOAT(OFS_PARM0) = armor;
G_FLOAT(OFS_PARM1) = blood;
G_VECTORSET(OFS_PARM2, from[0], from[1], from[2]);
PR_ExecuteProgram(cl.qcvm.extfuncs.CSQC_Parse_Damage);
inhibit = G_FLOAT(OFS_RETURN);
PR_SwitchQCVM(NULL);
if (inhibit)
return;
}
count = blood*0.5 + armor*0.5;
if (count < 10)
count = 10;

View file

@ -183,21 +183,6 @@ ENTITY AREA CHECKING
===============================================================================
*/
typedef struct areanode_s
{
int axis; // -1 = leaf node
float dist;
struct areanode_s *children[2];
link_t trigger_edicts;
link_t solid_edicts;
} areanode_t;
#define AREA_DEPTH 4
#define AREA_NODES 32
static areanode_t sv_areanodes[AREA_NODES];
static int sv_numareanodes;
/*
===============
SV_CreateAreaNode
@ -210,8 +195,8 @@ areanode_t *SV_CreateAreaNode (int depth, vec3_t mins, vec3_t maxs)
vec3_t size;
vec3_t mins1, maxs1, mins2, maxs2;
anode = &sv_areanodes[sv_numareanodes];
sv_numareanodes++;
anode = &qcvm->areanodes[qcvm->numareanodes];
qcvm->numareanodes++;
ClearLink (&anode->trigger_edicts);
ClearLink (&anode->solid_edicts);
@ -253,9 +238,9 @@ void SV_ClearWorld (void)
{
SV_InitBoxHull ();
memset (sv_areanodes, 0, sizeof(sv_areanodes));
sv_numareanodes = 0;
SV_CreateAreaNode (0, sv.worldmodel->mins, sv.worldmodel->maxs);
memset (qcvm->areanodes, 0, sizeof(qcvm->areanodes));
qcvm->numareanodes = 0;
SV_CreateAreaNode (0, qcvm->worldmodel->mins, qcvm->worldmodel->maxs);
}
@ -341,10 +326,10 @@ void SV_TouchLinks (edict_t *ent)
int mark;
mark = Hunk_LowMark ();
list = (edict_t **) Hunk_Alloc (sv.num_edicts*sizeof(edict_t *));
list = (edict_t **) Hunk_Alloc (qcvm->num_edicts*sizeof(edict_t *));
listcount = 0;
SV_AreaTriggerEdicts (ent, sv_areanodes, list, &listcount, sv.num_edicts);
SV_AreaTriggerEdicts (ent, qcvm->areanodes, list, &listcount, qcvm->num_edicts);
for (i = 0; i < listcount; i++)
{
@ -367,7 +352,7 @@ void SV_TouchLinks (edict_t *ent)
pr_global_struct->self = EDICT_TO_PROG(touch);
pr_global_struct->other = EDICT_TO_PROG(ent);
pr_global_struct->time = sv.time;
pr_global_struct->time = qcvm->time;
PR_ExecuteProgram (touch->v.touch);
pr_global_struct->self = old_self;
@ -403,7 +388,7 @@ void SV_FindTouchedLeafs (edict_t *ent, mnode_t *node)
return;
leaf = (mleaf_t *)node;
leafnum = leaf - sv.worldmodel->leafs - 1;
leafnum = leaf - qcvm->worldmodel->leafs - 1;
ent->leafnums[ent->num_leafs] = leafnum;
ent->num_leafs++;
@ -436,7 +421,7 @@ void SV_LinkEdict (edict_t *ent, qboolean touch_triggers)
if (ent->area.prev)
SV_UnlinkEdict (ent); // unlink from old position
if (ent == sv.edicts)
if (ent == qcvm->edicts)
return; // don't add the world
if (ent->free)
@ -471,13 +456,13 @@ void SV_LinkEdict (edict_t *ent, qboolean touch_triggers)
// link to PVS leafs
ent->num_leafs = 0;
if (ent->v.modelindex)
SV_FindTouchedLeafs (ent, sv.worldmodel->nodes);
SV_FindTouchedLeafs (ent, qcvm->worldmodel->nodes);
if (ent->v.solid == SOLID_NOT)
return;
// find the first node that the ent's box crosses
node = sv_areanodes;
node = qcvm->areanodes;
while (1)
{
if (node->axis == -1)
@ -556,7 +541,7 @@ int SV_PointContents (vec3_t p)
{
int cont;
cont = SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p);
cont = SV_HullPointContents (&qcvm->worldmodel->hulls[0], 0, p);
if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN)
cont = CONTENTS_WATER;
return cont;
@ -564,7 +549,7 @@ int SV_PointContents (vec3_t p)
int SV_TruePointContents (vec3_t p)
{
return SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p);
return SV_HullPointContents (&qcvm->worldmodel->hulls[0], 0, p);
}
//===========================================================================
@ -583,7 +568,7 @@ edict_t *SV_TestEntityPosition (edict_t *ent)
trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, 0, ent);
if (trace.startsolid)
return sv.edicts;
return qcvm->edicts;
return NULL;
}
@ -916,7 +901,7 @@ trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, e
memset ( &clip, 0, sizeof ( moveclip_t ) );
// clip to world
clip.trace = SV_ClipMoveToEntity ( sv.edicts, start, mins, maxs, end );
clip.trace = SV_ClipMoveToEntity ( qcvm->edicts, start, mins, maxs, end );
clip.start = start;
clip.end = end;
@ -943,7 +928,7 @@ trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, e
SV_MoveBounds ( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs );
// clip to entities
SV_ClipToLinks ( sv_areanodes, &clip );
SV_ClipToLinks ( qcvm->areanodes, &clip );
return clip.trace;
}

View file

@ -36,6 +36,11 @@ QuakeSpasm-Spiked
copy of regular QuakeSpasm, you should be able to have both installed in
the same game directory without issue - on the condition that they're
both win32 or both win64, not a mix.
Note that advanced users can use the -basedir argument in order to install
engines within sub-dirs/where-ever in order to avoid conflicts be they
win32 vs win64, qs vs qss, or even qss vs any other engine - this argument
should exist in ALL quake engines, and thus it need not be just qss that
is given it. However, this will not prevent other sorts of conflicts.
-------------
3. New Toys!