Menuqc support. Only tested against menusys so far.

This commit is contained in:
Shpoike 2020-07-02 20:05:51 +01:00
parent 4c9569c254
commit 54538a054a
28 changed files with 1920 additions and 608 deletions

View file

@ -144,6 +144,9 @@ typedef struct
char temp[MAX_OSPATH]; //the temp filename for the download, will be renamed to current
float starttime;
} download;
//Spike -- menuqc stuff.
qcvm_t menu_qcvm;
} client_static_t;
extern client_static_t cls;
@ -290,7 +293,6 @@ typedef struct
//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

@ -694,19 +694,16 @@ Cmd_AddCommand
spike -- added an extra arg for client (also renamed and made a macro)
============
*/
void Cmd_AddCommand2 (const char *cmd_name, xcommand_t function, cmd_source_t srctype)
cmd_function_t *Cmd_AddCommand2 (const char *cmd_name, xcommand_t function, cmd_source_t srctype)
{
cmd_function_t *cmd;
cmd_function_t *cursor,*prev; //johnfitz -- sorted list insert
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
if (Cvar_VariableString(cmd_name)[0])
{
Con_Printf ("Cmd_AddCommand: %s already defined as a var\n", cmd_name);
return;
return NULL;
}
// fail if the command already exists
@ -716,15 +713,22 @@ void Cmd_AddCommand2 (const char *cmd_name, xcommand_t function, cmd_source_t sr
{
if (cmd->function != function && function)
Con_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name);
return;
return NULL;
}
}
if (host_initialized)
cmd = malloc(sizeof(cmd_function_t));
{
cmd = (cmd_function_t *) malloc(sizeof(*cmd) + strlen(cmd_name)+1);
cmd->name = strcpy((char*)(cmd + 1), cmd_name);
cmd->dynamic = true;
}
else
cmd = (cmd_function_t *) Hunk_Alloc (sizeof(cmd_function_t));
cmd->name = cmd_name;
{
cmd = (cmd_function_t *) Hunk_Alloc (sizeof(*cmd));
cmd->name = cmd_name;
cmd->dynamic = false;
}
cmd->function = function;
cmd->srctype = srctype;
@ -747,6 +751,24 @@ void Cmd_AddCommand2 (const char *cmd_name, xcommand_t function, cmd_source_t sr
prev->next = cmd;
}
//johnfitz
if (cmd->dynamic)
return cmd;
return NULL;
}
void Cmd_RemoveCommand (cmd_function_t *cmd)
{
cmd_function_t **link;
for (link = &cmd_functions; *link; link = &(*link)->next)
{
if (*link == cmd)
{
*link = cmd->next;
free(cmd);
return;
}
}
Sys_Error ("Cmd_RemoveCommand unable to remove command %s",cmd->name);
}
/*
@ -827,20 +849,26 @@ qboolean Cmd_ExecuteString (const char *text, cmd_source_t src)
cmd->function ();
else
{
if (cl.qcvm.extfuncs.CSQC_ConsoleCommand)
qboolean ret = false;
if (!ret && 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
if (!ret && cls.menu_qcvm.extfuncs.m_consolecommand)
{
PR_SwitchQCVM(&cls.menu_qcvm);
G_INT(OFS_PARM0) = PR_MakeTempString(text);
PR_ExecuteProgram(cls.menu_qcvm.extfuncs.m_consolecommand);
ret = G_FLOAT(OFS_RETURN);
PR_SwitchQCVM(NULL);
}
if (!ret)
Con_Printf ("gamecode not running, cannot \"%s\"\n", Cmd_Argv(0));
return true;
}
return true;
}

View file

@ -94,11 +94,13 @@ typedef struct cmd_function_s
const char *name;
xcommand_t function;
cmd_source_t srctype;
qboolean dynamic;
} cmd_function_t;
void Cmd_Init (void);
void Cmd_AddCommand2 (const char *cmd_name, xcommand_t function, cmd_source_t srctype);
cmd_function_t *Cmd_AddCommand2 (const char *cmd_name, xcommand_t function, cmd_source_t srctype);
void Cmd_RemoveCommand (cmd_function_t *cmd);
// called by the init functions of other parts of the program to
// register commands and functions to call for them.
// The cmd_name is referenced later, so it should not be in temp memory

View file

@ -556,6 +556,54 @@ float Q_atof (const char *str)
return val*sign;
}
// Q_ftoa: convert IEEE 754 float to a base-10 string with "infinite" decimal places
void Q_ftoa(char *str, float in)
{
unsigned int i = *((int *)&in);
int signbit = (i & 0x80000000) >> 31;
int exp = (signed int)((i & 0x7F800000) >> 23) - 127;
int mantissa = (i & 0x007FFFFF);
if (exp == 128) // 255(NaN/Infinity bits) - 127(bias)
{
if (signbit)
{
*str = '-';
str++;
}
if (mantissa == 0) // infinity
strcpy(str, "1.#INF");
else // NaN or indeterminate
strcpy(str, "1.#NAN");
return;
}
exp = -exp;
exp = (int)(exp * 0.30102999957f); // convert base 2 to base 10
exp += 8;
if (exp <= 0)
sprintf(str, "%.0f", in);
else
{
char tstr[32];
char *lsig = str - 1;
sprintf(tstr, "%%.%if", exp);
sprintf(str, tstr, in);
// find last significant digit and trim
while (*str)
{
if (*str >= '1' && *str <= '9')
lsig = str;
else if (*str == '.')
lsig = str - 1;
str++;
}
lsig[1] = '\0';
}
}
/*
============================================================================
@ -1626,7 +1674,7 @@ typedef struct
int dirlen;
} dpackheader_t;
#define MAX_FILES_IN_PACK 2048
#define MAX_FILES_IN_PACK 4096
char com_gamenames[1024]; //eg: "hipnotic;quoth;warp", no id1, no private stuff
char com_gamedir[MAX_OSPATH];

View file

@ -140,6 +140,7 @@ int Q_strcmp (const char *s1, const char *s2);
int Q_strncmp (const char *s1, const char *s2, int count);
int Q_atoi (const char *str);
float Q_atof (const char *str);
void Q_ftoa(char *str, float in);
#include "strl_fn.h"

View file

@ -119,10 +119,13 @@ void Con_ToggleConsole_f (void)
if (cls.state == ca_connected)
key_dest = key_game;
else
M_Menu_Main_f ();
M_ToggleMenu(1);
}
else
{
M_ToggleMenu(0);
key_dest = key_console;
}
SCR_EndLoadingPlaque ();
memset (con_times, 0, sizeof(con_times));
@ -607,7 +610,7 @@ void Con_Printf (const char *fmt, ...)
Con_Print (msg);
// update the screen if the console is displayed
if (cls.signon != SIGNONS && !scr_disabled_for_loading )
if (cls.signon != SIGNONS && !scr_disabled_for_loading && !qcvm)
{
// protect against infinite loop if something in SCR_UpdateScreen calls
// Con_Printd

View file

@ -272,6 +272,8 @@ void R_PushDlights (void)
r_dlightframecount = r_framecount + 1; // because the count hasn't
// advanced yet for this frame
if (!r_refdef.drawworld)
return;
l = cl_dlights;
for (i=0 ; i<MAX_DLIGHTS ; i++, l++)

View file

@ -533,7 +533,7 @@ void R_Clear (void)
// from mh -- if we get a stencil buffer, we should clear it, even though we don't use it
if (gl_stencilbits)
clearbits |= GL_STENCIL_BUFFER_BIT;
if (gl_clear.value && !skyroom_drawn)
if (gl_clear.value && !skyroom_drawn && r_refdef.drawworld)
clearbits |= GL_COLOR_BUFFER_BIT;
glClear (clearbits);
}
@ -566,35 +566,40 @@ void R_SetupView (void)
VectorCopy (r_refdef.vieworg, r_origin);
AngleVectors (r_refdef.viewangles, vpn, vright, vup);
// current viewleaf
r_oldviewleaf = r_viewleaf;
r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel);
viewcontents = r_viewleaf->contents;
//spike -- FTE_ENT_SKIN_CONTENTS -- added this loop for moving water volumes, to avoid v_cshift etc hacks.
for (i = 0; i < cl.num_entities && viewcontents == CONTENTS_EMPTY; i++)
if (r_refdef.drawworld)
{
mleaf_t *subleaf;
vec3_t relpos;
if (cl.entities[i].model && cl.entities[i].model->type==mod_brush)
// current viewleaf
r_oldviewleaf = r_viewleaf;
r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel);
viewcontents = r_viewleaf->contents;
//spike -- FTE_ENT_SKIN_CONTENTS -- added this loop for moving water volumes, to avoid v_cshift etc hacks.
for (i = 0; i < cl.num_entities && viewcontents == CONTENTS_EMPTY; i++)
{
VectorSubtract(r_origin, cl.entities[i].origin, relpos);
if (cl.entities[i].angles[0] || cl.entities[i].angles[1] || cl.entities[i].angles[2])
{ //rotate the point, just in case.
vec3_t axis[3], t;
AngleVectors(cl.entities[i].angles, axis[0], axis[1], axis[2]);
VectorCopy(relpos, t);
relpos[0] = DotProduct(t, axis[0]);
relpos[0] = -DotProduct(t, axis[1]);
relpos[0] = DotProduct(t, axis[2]);
mleaf_t *subleaf;
vec3_t relpos;
if (cl.entities[i].model && cl.entities[i].model->type==mod_brush)
{
VectorSubtract(r_origin, cl.entities[i].origin, relpos);
if (cl.entities[i].angles[0] || cl.entities[i].angles[1] || cl.entities[i].angles[2])
{ //rotate the point, just in case.
vec3_t axis[3], t;
AngleVectors(cl.entities[i].angles, axis[0], axis[1], axis[2]);
VectorCopy(relpos, t);
relpos[0] = DotProduct(t, axis[0]);
relpos[0] = -DotProduct(t, axis[1]);
relpos[0] = DotProduct(t, axis[2]);
}
subleaf = Mod_PointInLeaf (relpos, cl.entities[i].model);
if ((char)cl.entities[i].skinnum < 0)
viewcontents = ((subleaf->contents == CONTENTS_SOLID)?(char)cl.entities[i].skinnum:CONTENTS_EMPTY);
else
viewcontents = subleaf->contents;
}
subleaf = Mod_PointInLeaf (relpos, cl.entities[i].model);
if ((char)cl.entities[i].skinnum < 0)
viewcontents = ((subleaf->contents == CONTENTS_SOLID)?(char)cl.entities[i].skinnum:CONTENTS_EMPTY);
else
viewcontents = subleaf->contents;
}
}
else
viewcontents = CONTENTS_EMPTY;
V_SetContentsColor (viewcontents);
V_CalcBlend ();
@ -617,19 +622,22 @@ void R_SetupView (void)
R_SetFrustum (r_fovx, r_fovy); //johnfitz -- use r_fov* vars
R_MarkSurfaces (); //johnfitz -- create texture chains from PVS
if (r_refdef.drawworld)
{
R_MarkSurfaces (); //johnfitz -- create texture chains from PVS
R_CullSurfaces (); //johnfitz -- do after R_SetFrustum and R_MarkSurfaces
R_CullSurfaces (); //johnfitz -- do after R_SetFrustum and R_MarkSurfaces
if (!skyroom_drawn)
R_UpdateWarpTextures (); //johnfitz -- do this before R_Clear
if (!skyroom_drawn)
R_UpdateWarpTextures (); //johnfitz -- do this before R_Clear
}
R_Clear ();
//johnfitz -- cheat-protect some draw modes
r_drawflat_cheatsafe = r_fullbright_cheatsafe = r_lightmap_cheatsafe = false;
r_drawworld_cheatsafe = true;
if (cl.maxclients == 1)
r_drawworld_cheatsafe = r_refdef.drawworld;
if (cl.maxclients == 1 && r_refdef.drawworld)
{
if (!r_drawworld.value) r_drawworld_cheatsafe = false;
@ -984,10 +992,13 @@ void R_RenderScene (void)
R_RenderDlights (); //triangle fan dlights -- johnfitz -- moved after water
R_DrawParticles ();
if (r_refdef.drawworld)
{
R_DrawParticles ();
#ifdef PSET_SCRIPT
PScript_DrawParticles();
PScript_DrawParticles();
#endif
}
Fog_DisableGFog (); //johnfitz

View file

@ -1155,6 +1155,7 @@ void SCR_UpdateScreen (void)
//
// determine size of refresh window
//
r_refdef.drawworld = true;
if (vid.recalc_refdef)
SCR_CalcRefdef ();

View file

@ -1464,6 +1464,10 @@ gltexture_t *TexMgr_LoadImage (qmodel_t *owner, const char *name, int width, int
glt->width = glt->source_width;
glt->height = glt->source_height;
TexMgr_LoadImage8 (glt, (byte*)"\x07");
glt->source_width = glt->source_height = 0;
glt->width = glt->source_width;
glt->height = glt->source_height;
}
else
{

View file

@ -173,6 +173,8 @@ void Host_Error (const char *error, ...)
if (cl.qcvm.progs)
glDisable(GL_SCISSOR_TEST); //equivelent to drawresetcliparea, to reset any damage if we crashed in csqc.
if (qcvm == &cls.menu_qcvm)
MQC_Shutdown();
PR_SwitchQCVM(NULL);
SCR_EndLoadingPlaque (); // reenable screen updates
@ -767,8 +769,8 @@ void _Host_Frame (double time)
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))
if ((PR_LoadProgs("csprogs.dat", false, PROGHEADER_CRC, pr_csqcbuiltins, pr_csqcnumbuiltins) && qcvm->extfuncs.CSQC_DrawHud)||
(PR_LoadProgs("progs.dat", false, PROGHEADER_CRC, 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);
@ -970,7 +972,6 @@ void Host_Init (void)
V_Init ();
Chase_Init ();
M_Init ();
ExtraMaps_Init (); //johnfitz
Modlist_Init (); //johnfitz
DemoList_Init (); //ericw
@ -993,6 +994,16 @@ void Host_Init (void)
host_initialized = true;
Con_Printf ("\n========= Quake Initialized =========\n\n");
//okay... now we can do stuff that's allowed to Host_Error
if (setjmp (host_abortserver) )
return; // something bad happened
if (cls.state != ca_dedicated)
M_Init ();
if (setjmp (host_abortserver) )
return; // don't do the above twice if the following Cbuf_Execute does bad things.
//spike -- create these aliases, because they're useful.
Cbuf_AddText ("alias startmap_sp \"map start\"\n");
Cbuf_AddText ("alias startmap_dm \"map start\"\n");

View file

@ -40,7 +40,7 @@ Host_Quit_f
void Host_Quit_f (void)
{
if (key_dest != key_console && cls.state != ca_dedicated)
if (key_dest != key_console && cls.state != ca_dedicated && !cls.menu_qcvm.progs)
{
M_Menu_Quit_f ();
return;
@ -429,6 +429,9 @@ void Host_Status_f (void)
int hours = 0;
int j, i;
qhostaddr_t addresses[32];
int numaddresses;
if (cmd_source == src_command)
{
if (!sv.active)
@ -443,12 +446,24 @@ void Host_Status_f (void)
print_fn ( "host: %s\n", Cvar_VariableString ("hostname"));
print_fn ( "version: "ENGINE_NAME_AND_VER"\n");
#if 1
numaddresses = NET_ListAddresses(addresses, sizeof(addresses)/sizeof(addresses[0]));
for (i = 0; i < numaddresses; i++)
{
if (*addresses[i] == '[')
print_fn ("ipv6: %s\n", addresses[i]); //Spike -- FIXME: we should really have ports displayed here or something
else
print_fn ("tcp/ip: %s\n", addresses[i]); //Spike -- FIXME: we should really have ports displayed here or something
}
#else
if (ipv4Available)
print_fn ("tcp/ip: %s\n", my_ipv4_address); //Spike -- FIXME: we should really have ports displayed here or something
if (ipv6Available)
print_fn ("ipv6: %s\n", my_ipv6_address);
if (ipxAvailable)
print_fn ("ipx: %s\n", my_ipx_address);
#endif
print_fn ( "map: %s\n", sv.name);
for (i = 1,j=0; i < MAX_MODELS; i++)
@ -2473,7 +2488,7 @@ void Host_Startdemos_f (void)
{ /* QuakeSpasm customization: */
/* go straight to menu, no CL_NextDemo */
cls.demonum = -1;
Cbuf_InsertText("menu_main\n");
Cbuf_InsertText("togglemenu 1\n");
return;
}
CL_NextDemo ();

View file

@ -83,6 +83,10 @@ static int buttonremap[] =
/* total accumulated mouse movement since last frame */
static int total_dx, total_dy = 0;
#if 1
static void IN_BeginIgnoringMouseEvents(void){}
static void IN_EndIgnoringMouseEvents(void){}
#else
static int SDLCALL IN_FilterMouseEvents (const SDL_Event *event)
{
switch (event->type)
@ -130,6 +134,7 @@ static void IN_EndIgnoringMouseEvents(void)
SDL_SetEventFilter(NULL);
#endif
}
#endif
#ifdef MACOS_X_ACCELERATION_HACK
static cvar_t in_disablemacosxmouseaccel = {"in_disablemacosxmouseaccel", "1", CVAR_ARCHIVE};
@ -284,8 +289,8 @@ static void IN_UpdateGrabs_Internal(qboolean forecerelease)
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));
wantcursor = (key_dest == key_console || (key_dest == key_menu&&!bind_grab)) || (key_dest == key_game && cl.qcvm.cursorforced);
freemouse = wantcursor && (modestate == MS_WINDOWED || (key_dest == key_game && cl.qcvm.cursorforced));
needevents = (!wantcursor) || key_dest == key_game;
if (isDedicated)
@ -430,10 +435,10 @@ void IN_Init (void)
if (SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL) == -1)
Con_Printf("Warning: SDL_EnableKeyRepeat() failed.\n");
#else
if (textmode)
SDL_StartTextInput();
else
SDL_StopTextInput();
// if (textmode)
// SDL_StartTextInput();
// else
// SDL_StopTextInput();
#endif
if (safemode || COM_CheckParm("-nomouse"))
{
@ -472,12 +477,40 @@ extern cvar_t cl_minpitch; /* johnfitz -- variable pitch clamping */
void IN_MouseMotion(int dx, int dy, int wx, int wy)
{
if (key_dest != key_game && key_dest != key_message)
vid.cursorpos[0] = wx;
vid.cursorpos[1] = wy;
if (key_dest == key_menu && cls.menu_qcvm.extfuncs.Menu_InputEvent)
{
PR_SwitchQCVM(&cls.menu_qcvm);
if (qcvm->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(qcvm->extfuncs.Menu_InputEvent);
if (G_FLOAT(OFS_RETURN) || qcvm->cursorforced)
dx = dy = 0; //if the qc says it handled it, swallow the movement.
PR_SwitchQCVM(NULL);
}
else 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)
if (qcvm->cursorforced)
{
float s = CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0);
wx /= s;
@ -496,7 +529,7 @@ void IN_MouseMotion(int dx, int dy, int wx, int wy)
G_VECTORSET(OFS_PARM3, 0, 0, 0); //devid
}
PR_ExecuteProgram(cl.qcvm.extfuncs.CSQC_InputEvent);
if (G_FLOAT(OFS_RETURN) || cl.csqc_cursorforced)
if (G_FLOAT(OFS_RETURN) || qcvm->cursorforced)
dx = dy = 0; //if the qc says it handled it, swallow the movement.
PR_SwitchQCVM(NULL);
}
@ -859,7 +892,7 @@ void IN_ClearStates (void)
void IN_UpdateInputMode (void)
{
qboolean want_textmode = Key_TextEntry();
if (textmode != want_textmode)
if (0)//textmode != want_textmode)
{
textmode = want_textmode;
#if !defined(USE_SDL2)
@ -952,7 +985,7 @@ static inline int IN_SDL_KeysymToQuakeKey(SDLKey sym)
case SDLK_BREAK: return K_PAUSE;
case SDLK_PAUSE: return K_PAUSE;
case SDLK_WORLD_18: return '~'; // the '²' key
case SDLK_WORLD_18: return '~'; // the '²' key
default: return 0;
}

View file

@ -1279,10 +1279,37 @@ void Key_GetGrabbedInput (int *lastkey, int *lastchar)
*lastchar = key_inputgrab.lastchar;
}
qboolean Menu_HandleKeyEvent(qboolean down, int keyc, int unic)
{
qboolean inhibit = false;
if (key_dest != key_menu)
;
else if (cls.menu_qcvm.extfuncs.Menu_InputEvent)
{
PR_SwitchQCVM(&cls.menu_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(cls.menu_qcvm.extfuncs.Menu_InputEvent);
inhibit = G_FLOAT(OFS_RETURN);
PR_SwitchQCVM(NULL);
}
else if (down?cls.menu_qcvm.extfuncs.m_keydown:cls.menu_qcvm.extfuncs.m_keyup)
{
PR_SwitchQCVM(&cls.menu_qcvm);
G_FLOAT(OFS_PARM0) = Key_NativeToQC(keyc); //scancode
G_FLOAT(OFS_PARM1) = unic; //unicode
PR_ExecuteProgram(down?cls.menu_qcvm.extfuncs.m_keydown:cls.menu_qcvm.extfuncs.m_keyup);
inhibit = G_FLOAT(OFS_RETURN);
PR_SwitchQCVM(NULL);
}
return inhibit;
}
qboolean CSQC_HandleKeyEvent(qboolean down, int keyc, int unic)
{
qboolean inhibit = false;
if (cl.qcvm.extfuncs.CSQC_InputEvent && key_dest == key_game)
if (cl.qcvm.extfuncs.CSQC_InputEvent && (key_dest == key_game || !down))
{
PR_SwitchQCVM(&cl.qcvm);
G_FLOAT(OFS_PARM0) = down?CSIE_KEYDOWN:CSIE_KEYUP;
@ -1293,7 +1320,9 @@ qboolean CSQC_HandleKeyEvent(qboolean down, int keyc, int unic)
inhibit = G_FLOAT(OFS_RETURN);
PR_SwitchQCVM(NULL);
}
return inhibit;
if (key_dest == key_game)
return inhibit;
return false;
}
/*
@ -1345,13 +1374,15 @@ void Key_Event (int key, qboolean down)
{
if (!down)
{
Menu_HandleKeyEvent(down, key, 0);
CSQC_HandleKeyEvent(down, key, 0); //Spike -- for consistency
return;
}
if (keydown[K_SHIFT])
{
Con_ToggleConsole_f();
{ //shift+escape forces the console (without closing it again - use a regular escape to get rid fo it after, making it easier to type blind).
if (key_dest != key_console)
Con_ToggleConsole_f();
return;
}
@ -1361,13 +1392,14 @@ void Key_Event (int key, qboolean down)
Key_Message (key);
break;
case key_menu:
M_Keydown (key);
if (!Menu_HandleKeyEvent(down, key, 0))
M_Keydown (key);
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 ();
M_ToggleMenu(1);
break;
default:
Sys_Error ("Bad key_dest");
@ -1376,8 +1408,11 @@ 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))
//Spike -- give menuqc a chance to handle (and swallow) key events.
if ((key_dest == key_menu || !down) && Menu_HandleKeyEvent(down, key, 0))
return;
//Spike -- give csqc a chance to handle (and swallow) key events.
if ((key_dest == key_game || !down) && CSQC_HandleKeyEvent(down, key, 0))
return;
// key up events only generate commands if the game key binding is
@ -1401,7 +1436,7 @@ void Key_Event (int key, qboolean down)
// during demo playback, most keys bring up the main menu
if (cls.demoplayback && down && consolekeys[key] && key_dest == key_game && key != K_TAB)
{
M_ToggleMenu_f ();
M_ToggleMenu (1);
return;
}
@ -1483,7 +1518,8 @@ void Char_Event (int key)
Char_Message (key);
break;
case key_menu:
M_Charinput (key);
if (!Menu_HandleKeyEvent(true, 0, key))
M_Charinput (key);
break;
case key_game:
if (!con_forcedup)

View file

@ -201,39 +201,6 @@ void M_DrawTextBox (int x, int y, int width, int lines)
int m_save_demonum;
/*
================
M_ToggleMenu_f
================
*/
void M_ToggleMenu_f (void)
{
m_entersound = true;
if (key_dest == key_menu)
{
if (m_state != m_main)
{
M_Menu_Main_f ();
return;
}
key_dest = key_game;
m_state = m_none;
IN_UpdateGrabs();
return;
}
if (key_dest == key_console)
{
Con_ToggleConsole_f ();
}
else
{
M_Menu_Main_f ();
}
}
//=============================================================================
/* MAIN MENU */
@ -2733,30 +2700,205 @@ void M_ServerList_Key (int k)
}
static struct
{
const char *name;
xcommand_t function;
cmd_function_t *cmd;
} menucommands[] =
{
{"menu_main", M_Menu_Main_f},
{"menu_singleplayer", M_Menu_SinglePlayer_f},
{"menu_load", M_Menu_Load_f},
{"menu_save", M_Menu_Save_f},
{"menu_multiplayer", M_Menu_MultiPlayer_f},
{"menu_setup", M_Menu_Setup_f},
{"menu_options", M_Menu_Options_f},
{"menu_keys", M_Menu_Keys_f},
{"menu_video", M_Menu_Video_f},
{"help", M_Menu_Help_f},
{"menu_quit", M_Menu_Quit_f},
};
//=============================================================================
/* MenuQC Subsystem */
extern builtin_t pr_menubuiltins[];
extern int pr_menunumbuiltins;
#define MENUQC_PROGHEADER_CRC 10020
void MQC_End(void)
{
PR_SwitchQCVM(NULL);
}
void MQC_Begin(void)
{
PR_SwitchQCVM(&cls.menu_qcvm);
pr_global_struct = NULL;
}
static qboolean MQC_Init(void)
{
size_t i;
qboolean success;
PR_SwitchQCVM(&cls.menu_qcvm);
if (COM_CheckParm("-qmenu") || fitzmode || !pr_checkextension.value)
success = false;
else
success = PR_LoadProgs("menu.dat", false, MENUQC_PROGHEADER_CRC, pr_menubuiltins, pr_menunumbuiltins);
if (success && qcvm->extfuncs.m_draw)
{
for (i = 0; i < sizeof(menucommands)/sizeof(menucommands[0]); i++)
if (menucommands[i].cmd)
{
Cmd_RemoveCommand (menucommands[i].cmd);
menucommands[i].cmd = NULL;
}
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);
if (qcvm->extfuncs.m_init)
PR_ExecuteProgram(qcvm->extfuncs.m_init);
}
PR_SwitchQCVM(NULL);
return success;
}
void MQC_Shutdown(void)
{
size_t i;
if (key_dest == key_menu)
key_dest = key_console;
PR_ClearProgs(&cls.menu_qcvm); //nuke it from orbit
for (i = 0; i < sizeof(menucommands)/sizeof(menucommands[0]); i++)
if (!menucommands[i].cmd)
menucommands[i].cmd = Cmd_AddCommand (menucommands[i].name, menucommands[i].function);
}
static void MQC_Command_f(void)
{
if (cls.menu_qcvm.extfuncs.GameCommand)
{
MQC_Begin();
G_INT(OFS_PARM0) = PR_MakeTempString(Cmd_Args());
PR_ExecuteProgram(qcvm->extfuncs.GameCommand);
MQC_End();
}
else
Con_Printf("menu_cmd: no menuqc GameCommand function available\n");
}
//=============================================================================
/* Menu Subsystem */
/*
================
M_ToggleMenu_f
================
*/
void M_ToggleMenu (int mode)
{
if (cls.menu_qcvm.extfuncs.m_toggle)
{
MQC_Begin();
G_FLOAT(OFS_PARM0) = mode;
PR_ExecuteProgram(qcvm->extfuncs.m_toggle);
MQC_End();
return;
}
m_entersound = true;
if (key_dest == key_menu)
{
if (mode != 0 && m_state != m_main)
{
M_Menu_Main_f ();
return;
}
key_dest = key_game;
m_state = m_none;
IN_UpdateGrabs();
return;
}
else if (mode == 0)
return;
if (mode == -1 && key_dest == key_console)
{
Con_ToggleConsole_f ();
}
else
{
M_Menu_Main_f ();
}
}
static void M_ToggleMenu_f (void)
{
M_ToggleMenu((Cmd_Argc() < 2) ? -1 : atoi(Cmd_Argv(1)));
}
static void M_MenuRestart_f (void)
{
qboolean off = !strcmp(Cmd_Argv(1), "off");
if (off || !MQC_Init())
MQC_Shutdown();
}
void M_Init (void)
{
Cmd_AddCommand ("togglemenu", M_ToggleMenu_f);
Cmd_AddCommand ("menu_cmd", MQC_Command_f);
Cmd_AddCommand ("menu_restart", M_MenuRestart_f); //qss still loads progs on hunk, so we can't do this safely.
Cmd_AddCommand ("menu_main", M_Menu_Main_f);
Cmd_AddCommand ("menu_singleplayer", M_Menu_SinglePlayer_f);
Cmd_AddCommand ("menu_load", M_Menu_Load_f);
Cmd_AddCommand ("menu_save", M_Menu_Save_f);
Cmd_AddCommand ("menu_multiplayer", M_Menu_MultiPlayer_f);
Cmd_AddCommand ("menu_setup", M_Menu_Setup_f);
Cmd_AddCommand ("menu_options", M_Menu_Options_f);
Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
Cmd_AddCommand ("menu_video", M_Menu_Video_f);
Cmd_AddCommand ("help", M_Menu_Help_f);
Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
if (!MQC_Init())
MQC_Shutdown();
}
void M_Draw (void)
{
if (cls.menu_qcvm.extfuncs.m_draw)
{ //Spike -- menuqc
float s = CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0);
if (!host_initialized)
return;
MQC_Begin();
if (scr_con_current && key_dest == key_menu)
{ //make sure we don't have the console getting drawn in the background making the menu unreadable.
//FIXME: rework console to show over the top of menuqc.
Draw_ConsoleBackground ();
S_ExtraUpdate ();
}
GL_SetCanvas (CANVAS_CSQC);
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);
if (qcvm->extglobals.time)
*qcvm->extglobals.time = realtime;
if (qcvm->extglobals.frametime)
*qcvm->extglobals.frametime = host_frametime;
G_FLOAT(OFS_PARM0+0) = vid.width/s;
G_FLOAT(OFS_PARM0+1) = vid.height/s;
G_FLOAT(OFS_PARM0+2) = 0;
PR_ExecuteProgram(qcvm->extfuncs.m_draw);
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);
MQC_End();
return;
}
if (m_state == m_none || key_dest != key_menu)
return;
@ -2865,6 +3007,9 @@ void M_Draw (void)
void M_Keydown (int key)
{
if (cls.menu_qcvm.extfuncs.m_draw) //don't get confused.
return;
switch (m_state)
{
case m_none:
@ -2939,6 +3084,9 @@ void M_Keydown (int key)
void M_Charinput (int key)
{
if (cls.menu_qcvm.extfuncs.m_draw) //don't get confused.
return;
switch (m_state)
{
case m_setup:

View file

@ -55,7 +55,8 @@ void M_Init (void);
void M_Keydown (int key);
void M_Charinput (int key);
qboolean M_TextEntry (void);
void M_ToggleMenu_f (void);
void M_ToggleMenu (int mode);
void MQC_Shutdown(void);
void M_Menu_Main_f (void);
void M_Menu_Options_f (void);

View file

@ -244,8 +244,9 @@ double SetNetTime(void);
typedef struct
{
char name[16];
char name[64];
char map[16];
char gamedir[16];
char cname[NET_NAMELEN];
int users;
int maxusers;

View file

@ -1833,13 +1833,10 @@ static qboolean _Datagram_SearchForHosts (qboolean xmit)
hostCacheCount++;
}
Info_ReadKey(info, "hostname", hostcache[n].name, sizeof(hostcache[n].name));
if (!*hostcache[n].name)
q_strlcpy(hostcache[n].name, "UNNAMED", sizeof(hostcache[n].name));
Info_ReadKey(info, "mapname", hostcache[n].map, sizeof(hostcache[n].map));
Info_ReadKey(info, "modname", tmp, sizeof(tmp));
if (!COM_GameDirMatches(tmp))
{
q_strlcpy(hostcache[n].name, va("{%s}", tmp), sizeof(hostcache[n].name));
q_strlcpy(hostcache[n].map, "", sizeof(hostcache[n].map));
}
Info_ReadKey(info, "modname", hostcache[n].gamedir, sizeof(hostcache[n].gamedir));
Info_ReadKey(info, "clients", tmp, sizeof(tmp));
hostcache[n].users = atoi(tmp);
@ -1922,6 +1919,8 @@ static qboolean _Datagram_SearchForHosts (qboolean xmit)
hostCacheCount++;
}
q_strlcpy(hostcache[n].name, MSG_ReadString(), sizeof(hostcache[n].name));
if (!*hostcache[n].name)
q_strlcpy(hostcache[n].name, "UNNAMED", sizeof(hostcache[n].name));
q_strlcpy(hostcache[n].map, MSG_ReadString(), sizeof(hostcache[n].map));
hostcache[n].users = MSG_ReadByte();
hostcache[n].maxusers = MSG_ReadByte();

View file

@ -44,51 +44,60 @@ static struct in6_addr myAddrv6;
sys_socket_t UDP4_Init (void)
{
int err;
char *tst;
char buff[MAXHOSTNAMELEN];
struct hostent *local;
struct qsockaddr addr;
if (COM_CheckParm ("-noudp") || COM_CheckParm ("-noudp4"))
return INVALID_SOCKET;
// determine my name & address
myAddr4 = htonl(INADDR_LOOPBACK);
if (gethostname(buff, MAXHOSTNAMELEN) != 0)
#ifdef __linux__
//gethostbyname(gethostname()) is only supported if the hostname can be looked up on an actual name server
//this means its usable as a test to see if other hosts can see it, but means we cannot use it to find out the local address.
//it also means stalls and slow loading and other undesirable behaviour, so lets stop doing this legacy junk.
//we probably have multiple interfaces nowadays anyway (wan and lan and wifi and localhost and linklocal addresses and zomgwtf).
#else
{
err = SOCKETERRNO;
Con_SafePrintf("UDP4_Init: gethostname failed (%s)\n",
socketerror(err));
}
else
{
buff[MAXHOSTNAMELEN - 1] = 0;
// determine my name & address
int err;
char buff[MAXHOSTNAMELEN];
struct hostent *local;
if (gethostname(buff, MAXHOSTNAMELEN) != 0)
{
err = SOCKETERRNO;
Con_SafePrintf("UDP4_Init: gethostname failed (%s)\n",
socketerror(err));
}
else
{
buff[MAXHOSTNAMELEN - 1] = 0;
#ifdef PLATFORM_OSX
// ericw -- if our hostname ends in ".local" (a macOS thing),
// don't bother calling gethostbyname(), because it blocks for a few seconds
// and then fails (on my system anyway.)
tst = strstr(buff, ".local");
if (tst && tst[6] == '\0')
{
Con_SafePrintf("UDP_Init: skipping gethostbyname for %s\n", buff);
}
else
// ericw -- if our hostname ends in ".local" (a macOS thing),
// don't bother calling gethostbyname(), because it blocks for a few seconds
// and then fails (on my system anyway.)
tst = strstr(buff, ".local");
if (tst && tst[6] == '\0')
{
Con_SafePrintf("UDP_Init: skipping gethostbyname for %s\n", buff);
}
else
#endif
if (!(local = gethostbyname(buff)))
{
Con_SafePrintf("UDP4_Init: gethostbyname failed (%s)\n",
hstrerror(h_errno));
}
else if (local->h_addrtype != AF_INET)
{
Con_SafePrintf("UDP4_Init: address from gethostbyname not IPv4\n");
}
else
{
myAddr4 = *(in_addr_t *)local->h_addr_list[0];
if (!(local = gethostbyname(buff)))
{
Con_SafePrintf("UDP4_Init: gethostbyname failed (%s)\n",
hstrerror(h_errno));
}
else if (local->h_addrtype != AF_INET)
{
Con_SafePrintf("UDP4_Init: address from gethostbyname not IPv4\n");
}
else
{
myAddr4 = *(in_addr_t *)local->h_addr_list[0];
}
}
}
#endif
if ((net_controlsocket4 = UDP4_OpenSocket(0)) == INVALID_SOCKET)
{
@ -844,12 +853,13 @@ int UDP6_GetAddrFromName (const char *name, struct qsockaddr *addr)
#ifdef __linux__ //sadly there is no posix standard for querying all ipv4+ipv6 addresses.
#include <ifaddrs.h>
static struct ifaddrs *iflist;
double iftime; //requery sometimes.
static double iftime; //requery sometimes.
static int UDP_GetAddresses(qhostaddr_t *addresses, int maxaddresses, int fam)
{
struct ifaddrs *ifa;
int result = 0;
double time = Sys_DoubleTime();
size_t l;
if (time - iftime > 1 && iflist)
{
freeifaddrs(iflist);
@ -867,7 +877,13 @@ static int UDP_GetAddresses(qhostaddr_t *addresses, int maxaddresses, int fam)
if (ifa->ifa_addr == NULL)
continue;
if (fam == ifa->ifa_addr->sa_family)
q_strlcpy(addresses[result++], UDP_AddrToString((struct qsockaddr*)ifa->ifa_addr, false), sizeof(addresses[0]));
{
q_strlcpy(addresses[result], UDP_AddrToString((struct qsockaddr*)ifa->ifa_addr, false), sizeof(addresses[0]));
l = strlen(addresses[result]); //trim any useless :0 port numbers.
if (l > 2 && !strcmp(addresses[result]+l-2, ":0"))
addresses[result][l-2] = 0;
result++;
}
}
return result;
}

View file

@ -96,8 +96,11 @@ static void PF_error (void)
s = PF_VarString(0);
Con_Printf ("======SERVER ERROR in %s:\n%s\n",
PR_GetString(qcvm->xfunction->s_name), s);
ed = PROG_TO_EDICT(pr_global_struct->self);
ED_Print (ed);
if (qcvm != &cls.menu_qcvm)
{
ed = PROG_TO_EDICT(pr_global_struct->self);
ED_Print (ed);
}
Host_Error ("Program error");
}
@ -1026,8 +1029,10 @@ static void PF_ftos (void)
s = PR_GetTempString();
if (v == (int)v)
sprintf (s, "%d",(int)v);
else if (!pr_checkextension.value)
sprintf (s, "%5.1f",v); //dodgy path
else
sprintf (s, "%5.1f",v);
Q_ftoa (s, v); //what's normally expected
G_INT(OFS_RETURN) = PR_SetEngineString(s);
}
@ -2067,3 +2072,130 @@ builtin_t pr_csqcbuiltins[] =
PF_NoCSQC,//PF_setspawnparms
};
int pr_csqcnumbuiltins = sizeof(pr_csqcbuiltins)/sizeof(pr_csqcbuiltins[0]);
///////////////////////////////////////////////////////////////////
//menuqc
static void PF_clientstate (void)
{
//be sure to return ca_connected for TRYING to connect even if no response yet. QSS is still blocking.
G_FLOAT(OFS_RETURN) = cls.state;
}
static void PF_cvar_menuhack (void)
{ //hack around menuqc expecting vid_conwidth/vid_conheight to work.
const char *str = G_STRING(OFS_PARM0);
if (!strcmp(str, "vid_conwidth"))
{
float s = CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0);
G_FLOAT(OFS_RETURN) = vid.width/s;
}
else if (!strcmp(str, "vid_conheight"))
{
float s = CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0);
G_FLOAT(OFS_RETURN) = vid.height/s;
}
else
G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
}
//as a DP-derived API, these builtin numbers are completely unrelated to the ssqc ones. expect problems.
#define PF_MenuQCToDo PF_Fixme
#define PF_MenuCQMess PF_Fixme
#define PF_MenuCQExt PF_Fixme
builtin_t pr_menubuiltins[] = {
PF_Fixme, //#0
PF_MenuCQExt, //#1 PF_checkextension
PF_error, //#2
PF_objerror, //#3
PF_MenuCQExt, //#4 PF_print
PF_MenuQCToDo, //#5 PF_cl_bprint,
PF_MenuQCToDo, //#6 PF_cl_sprint,
PF_MenuQCToDo, //#7 PF_menu_cprint,
PF_normalize, //#8
PF_vlen, //#9
PF_vectoyaw, //#10
PF_vectoangles, //#11
PF_random, //#12
PF_localcmd, //#13
PF_cvar_menuhack, //#14
PF_cvar_set, //#15
PF_dprint, //#16
PF_ftos, //#17
PF_fabs, //#18
PF_vtos, //#19
PF_MenuCQExt, //#20 PF_etos,
PF_MenuCQExt, //#21 PF_stof,
PF_Spawn, //#22
PF_Remove, //#23
PF_Find, //#24
PF_MenuCQExt, //#25 PF_FindFloat,
PF_MenuCQExt, //#26 PF_menu_findchain,
PF_MenuCQExt, //#27 PF_menu_findchainfloat,
PF_precache_file, //#28
PF_cl_precache_sound, //#29
PF_coredump, //#30
PF_traceon, //#31
PF_traceoff, //#32
PF_eprint, //#33
PF_rint, //#34
PF_floor, //#35
PF_ceil, //#36
PF_nextent, //#37
PF_MenuCQExt, //#38 PF_Sin,
PF_MenuCQExt, //#39 PF_Cos,
PF_MenuCQExt, //#40 PF_Sqrt,
PF_MenuCQExt, //#41 PF_randomvector,
PF_MenuCQExt, //#42 PF_registercvar,
PF_MenuCQExt, //#43 PF_min,
PF_MenuCQExt, //#44 PF_max,
PF_MenuCQExt, //#45 PF_bound,
PF_MenuCQExt, //#46 PF_pow,
PF_MenuCQExt, //#47 PF_CopyEntity,
PF_MenuCQExt, //#48 PF_fopen,
PF_MenuCQExt, //#49 PF_fclose,
PF_MenuCQExt, //#50 PF_fgets,
PF_MenuCQExt, //#51 PF_fputs,
PF_MenuCQExt, //#52 PF_strlen,
PF_MenuCQExt, //#53 PF_strcat,
PF_MenuCQExt, //#54 PF_substring,
PF_MenuCQExt, //#55 PF_stov,
PF_MenuCQExt, //#56 PF_strzone,
PF_MenuCQExt, //#57 PF_strunzone,
PF_MenuCQExt, //#58 PF_Tokenize,
PF_MenuCQExt, //#59 PF_ArgV,
PF_MenuCQExt, //#60 PF_isserver,
PF_MenuCQExt, //#61 PF_cl_clientcount,
PF_clientstate, //#62
PF_MenuCQExt, //#63 PF_cl_clientcommand,
PF_MenuCQExt, //#64 PF_cl_changelevel,
PF_MenuCQExt, //#65 PF_cl_localsound,
PF_MenuCQExt, //#66 PF_cl_getmousepos,
PF_MenuCQExt, //#67 PF_gettime,
PF_MenuCQExt, //#68 PF_loadfromdata,
PF_MenuCQExt, //#69 PF_loadfromfile,
PF_MenuCQExt, //#70 PF_mod,
PF_MenuCQExt, //#71 PF_menu_cvar_string,
PF_MenuCQExt, //#72 PF_crash,
PF_MenuCQExt, //#73 PF_stackdump,
PF_MenuCQExt, //#74 PF_search_begin,
PF_MenuCQExt, //#75 PF_search_end,
PF_MenuCQExt, //#76 PF_search_getsize,
PF_MenuCQExt, //#77 PF_search_getfilename,
PF_MenuCQExt, //#78 PF_chr2str,
PF_MenuCQExt, //#79 PF_etof,
PF_MenuCQExt, //#80 PF_ftoe,
PF_MenuCQExt, //#81 PF_IsNotNull,
PF_MenuCQExt, //#82 PF_altstr_count,
PF_MenuCQExt, //#83 PF_altstr_prepare,
PF_MenuCQExt, //#84 PF_altstr_get,
PF_MenuCQExt, //#85 PF_altstr_set,
PF_MenuCQExt, //#86 PF_altstr_ins,
PF_MenuCQExt, //#87 PF_FindFlags,
PF_MenuCQExt, //#88 PF_menu_findchainflags,
PF_MenuCQExt, //#89 PF_cvar_defstring,
//all other builtins will just have to use the extension system
};
int pr_menunumbuiltins = sizeof(pr_menubuiltins)/sizeof(pr_menubuiltins[0]);

View file

@ -1101,6 +1101,7 @@ void PR_ClearProgs(qcvm_t *vm)
if (qcvm->knownstrings)
Z_Free ((void *)qcvm->knownstrings);
free(qcvm->edicts); // ericw -- sv.edicts switched to use malloc()
free(qcvm->progs); // spike -- pr_progs switched to use malloc (so menuqc doesn't end up stuck on the early hunk nor wiped on every map change)
memset(qcvm, 0, sizeof(*qcvm));
qcvm = NULL;
@ -1112,14 +1113,14 @@ void PR_ClearProgs(qcvm_t *vm)
PR_LoadProgs
===============
*/
qboolean PR_LoadProgs (const char *filename, qboolean fatal, builtin_t *builtins, size_t numbuiltins)
qboolean PR_LoadProgs (const char *filename, qboolean fatal, unsigned int needcrc, builtin_t *builtins, size_t numbuiltins)
{
int i;
unsigned int u;
PR_ClearProgs(qcvm); //just in case.
qcvm->progs = (dprograms_t *)COM_LoadHunkFile (filename, NULL);
qcvm->progs = (dprograms_t *)COM_LoadMallocFile(filename, NULL);
if (!qcvm->progs)
return false;
@ -1142,7 +1143,7 @@ qboolean PR_LoadProgs (const char *filename, qboolean fatal, builtin_t *builtins
return false;
}
}
if (qcvm->progs->crc != PROGHEADER_CRC)
if (qcvm->progs->crc != needcrc)
{
if (fatal)
Host_Error ("%s system vars have been modified, progdefs.h is out of date", filename);

File diff suppressed because it is too large Load diff

View file

@ -67,7 +67,7 @@ void PR_Init (void);
void PR_ExecuteProgram (func_t fnum);
void PR_ClearProgs(qcvm_t *vm);
qboolean PR_LoadProgs (const char *filename, qboolean fatal, builtin_t *builtins, size_t numbuiltins);
qboolean PR_LoadProgs (const char *filename, qboolean fatal, unsigned int needcrc, builtin_t *builtins, size_t numbuiltins);
//from pr_ext.c
void PR_InitExtensions(void);
@ -160,7 +160,7 @@ char *PF_VarString (int first);
void PF_Fixme(void); //the 'unimplemented' builtin. woot.
struct pr_extfuncs_s
{ //various global qc entry points that might be called by the engine, if set.
{ //various global ssqc entry points that might be called by the engine, if set.
func_t EndFrame;
func_t SV_ParseClientCommand;
@ -178,11 +178,26 @@ struct pr_extfuncs_s
// 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.
//menuqc-specific entry points
func_t m_init;
func_t m_toggle; //-1: toggle, 0: clear, 1: force
func_t m_draw;
func_t m_keydown; //obsoleted by Menu_InputEvent, included for dp compat.
func_t m_keyup; //obsoleted by Menu_InputEvent, included for dp compat.
func_t m_consolecommand;
func_t Menu_InputEvent;
//generic entry points, albeit not necessarily implemented for more than one module.
func_t GameCommand;//obsoleted by m_consolecommand, included for dp compat.
};
extern cvar_t pr_checkextension; //if 0, extensions are disabled (unless they'd be fatal, but they're still spammy)
struct pr_extglobals_s
{
//menuqc things...
float *time;
float *frametime;
//csqc-specific globals...
float *cltime;
float *maxclients;
@ -272,6 +287,7 @@ struct qcvm_s
struct pr_extglobals_s extglobals;
struct pr_extfuncs_s extfuncs;
struct pr_extfields_s extfields;
qboolean cursorforced;
//was static inside pr_edict
char *strings;

View file

@ -902,43 +902,48 @@ void R_SetupAliasLighting (entity_t *e)
float radiansangle;
float *origin = e->origin;
if (e->eflags & EFLAGS_VIEWMODEL)
origin = r_refdef.vieworg;
R_LightPoint (origin);
//add dlights
for (i=0 ; i<MAX_DLIGHTS ; i++)
if (!r_refdef.drawworld)
lightcolor[0] = lightcolor[1] = lightcolor[2] = 255;
else
{
if (cl_dlights[i].die >= cl.time)
if (e->eflags & EFLAGS_VIEWMODEL)
origin = r_refdef.vieworg;
R_LightPoint (origin);
//add dlights
for (i=0 ; i<MAX_DLIGHTS ; i++)
{
VectorSubtract (origin, cl_dlights[i].origin, dist);
add = cl_dlights[i].radius - VectorLength(dist);
if (add > 0)
VectorMA (lightcolor, add, cl_dlights[i].color, lightcolor);
if (cl_dlights[i].die >= cl.time)
{
VectorSubtract (origin, cl_dlights[i].origin, dist);
add = cl_dlights[i].radius - VectorLength(dist);
if (add > 0)
VectorMA (lightcolor, add, cl_dlights[i].color, lightcolor);
}
}
}
// minimum light value on gun (24)
if (e == &cl.viewent)
{
add = 72.0f - (lightcolor[0] + lightcolor[1] + lightcolor[2]);
if (add > 0.0f)
// minimum light value on gun (24)
if (e == &cl.viewent)
{
lightcolor[0] += add / 3.0f;
lightcolor[1] += add / 3.0f;
lightcolor[2] += add / 3.0f;
add = 72.0f - (lightcolor[0] + lightcolor[1] + lightcolor[2]);
if (add > 0.0f)
{
lightcolor[0] += add / 3.0f;
lightcolor[1] += add / 3.0f;
lightcolor[2] += add / 3.0f;
}
}
}
// minimum light value on players (8)
if (e > cl.entities && e <= cl.entities + cl.maxclients)
{
add = 24.0f - (lightcolor[0] + lightcolor[1] + lightcolor[2]);
if (add > 0.0f)
// minimum light value on players (8)
if (e > cl.entities && e <= cl.entities + cl.maxclients)
{
lightcolor[0] += add / 3.0f;
lightcolor[1] += add / 3.0f;
lightcolor[2] += add / 3.0f;
add = 24.0f - (lightcolor[0] + lightcolor[1] + lightcolor[2]);
if (add > 0.0f)
{
lightcolor[0] += add / 3.0f;
lightcolor[1] += add / 3.0f;
lightcolor[2] += add / 3.0f;
}
}
}

View file

@ -127,6 +127,7 @@ typedef struct
float fov_x, fov_y;
int ambientlight;
qboolean drawworld;
} refdef_t;

View file

@ -988,8 +988,8 @@ 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, qcvm->extfields.traileffectnum)->_float;
state->emiteffectnum = GetEdictFieldValue(ent, qcvm->extfields.emiteffectnum)->_float;
state->traileffectnum = qcvm->extfields.traileffectnum>=0?GetEdictFieldValue(ent, qcvm->extfields.traileffectnum)->_float:0;
state->emiteffectnum = qcvm->extfields.emiteffectnum>=0?GetEdictFieldValue(ent, qcvm->extfields.emiteffectnum)->_float:0;
if ((val = GetEdictFieldValue(ent, qcvm->extfields.tag_entity)) && val->edict)
state->tagentity = NUM_FOR_EDICT(PROG_TO_EDICT(val->edict));
else
@ -3064,7 +3064,7 @@ void SV_SpawnServer (const char *server)
else sv.protocolflags = 0;
// load progs to get entity field count
PR_LoadProgs ("progs.dat", true, pr_ssqcbuiltins, pr_ssqcnumbuiltins);
PR_LoadProgs ("progs.dat", true, PROGHEADER_CRC, pr_ssqcbuiltins, pr_ssqcnumbuiltins);
// allocate server memory
/* Host_ClearMemory() called above already cleared the whole sv structure */

View file

@ -64,6 +64,7 @@ typedef struct
int maxwarpwidth;
int maxwarpheight;
pixel_t *direct; // direct drawing to framebuffer, if not NULL
float cursorpos[2];
} viddef_t;
extern viddef_t vid; // global video state

View file

@ -110,6 +110,8 @@ void W_LoadWadFile (void) //johnfitz -- filename is now hard-coded for honesty
{
lump_p->filepos = LittleLong(lump_p->filepos);
lump_p->size = LittleLong(lump_p->size);
if (lump_p->filepos + lump_p->size > com_filesize && !(lump_p->filepos + LittleLong(lump_p->disksize) > com_filesize))
lump_p->size = LittleLong(lump_p->disksize);
if (lump_p->filepos < 0 || lump_p->size < 0 || lump_p->filepos + lump_p->size > com_filesize)
{
if (lump_p->filepos > com_filesize || lump_p->size < 0)