mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2025-01-19 07:51:03 +00:00
Merge pull request #599 from earth-metal/master
Create "mods" submenu to allow changing "game" cvar via UI
This commit is contained in:
commit
41931d7a06
3 changed files with 274 additions and 6 deletions
|
@ -50,6 +50,7 @@ static void M_Menu_SaveGame_f(void);
|
||||||
static void M_Menu_PlayerConfig_f(void);
|
static void M_Menu_PlayerConfig_f(void);
|
||||||
static void M_Menu_DownloadOptions_f(void);
|
static void M_Menu_DownloadOptions_f(void);
|
||||||
static void M_Menu_Credits_f(void);
|
static void M_Menu_Credits_f(void);
|
||||||
|
static void M_Menu_Mods_f(void);
|
||||||
static void M_Menu_Multiplayer_f(void);
|
static void M_Menu_Multiplayer_f(void);
|
||||||
static void M_Menu_JoinServer_f(void);
|
static void M_Menu_JoinServer_f(void);
|
||||||
static void M_Menu_AddressBook_f(void);
|
static void M_Menu_AddressBook_f(void);
|
||||||
|
@ -84,7 +85,8 @@ M_IsGame(const char *gamename)
|
||||||
{
|
{
|
||||||
cvar_t *game = Cvar_Get("game", "", CVAR_LATCH | CVAR_SERVERINFO);
|
cvar_t *game = Cvar_Get("game", "", CVAR_LATCH | CVAR_SERVERINFO);
|
||||||
|
|
||||||
if (strcmp(game->string, gamename) == 0)
|
if (strcmp(game->string, gamename) == 0
|
||||||
|
|| (strcmp(gamename, BASEDIRNAME) == 0 && strcmp(game->string, "") == 0))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1955,6 +1957,140 @@ M_Menu_Credits_f(void)
|
||||||
M_PushMenu(M_Credits_MenuDraw, M_Credits_Key);
|
M_PushMenu(M_Credits_MenuDraw, M_Credits_Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MODS MENU
|
||||||
|
*/
|
||||||
|
|
||||||
|
static menuframework_s s_mods_menu;
|
||||||
|
static menulist_s s_mods_list;
|
||||||
|
static menuaction_s s_mods_apply_action;
|
||||||
|
static char mods_statusbar[64];
|
||||||
|
|
||||||
|
static char **modnames = NULL;
|
||||||
|
static int nummods;
|
||||||
|
|
||||||
|
static void
|
||||||
|
Mods_NamesInit(void)
|
||||||
|
{
|
||||||
|
/* initialize list of mods once, reuse it afterwards (=> it isn't freed) */
|
||||||
|
if (modnames == NULL)
|
||||||
|
{
|
||||||
|
modnames = FS_ListMods(&nummods);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ModsListFunc(void *unused)
|
||||||
|
{
|
||||||
|
if (strcmp(BASEDIRNAME, modnames[s_mods_list.curvalue]) == 0)
|
||||||
|
{
|
||||||
|
strcpy(mods_statusbar, "Quake II");
|
||||||
|
}
|
||||||
|
else if (strcmp("ctf", modnames[s_mods_list.curvalue]) == 0)
|
||||||
|
{
|
||||||
|
strcpy(mods_statusbar, "Quake II Capture The Flag");
|
||||||
|
}
|
||||||
|
else if (strcmp("rogue", modnames[s_mods_list.curvalue]) == 0)
|
||||||
|
{
|
||||||
|
strcpy(mods_statusbar, "Quake II Mission Pack: Ground Zero");
|
||||||
|
}
|
||||||
|
else if (strcmp("xatrix", modnames[s_mods_list.curvalue]) == 0)
|
||||||
|
{
|
||||||
|
strcpy(mods_statusbar, "Quake II Mission Pack: The Reckoning");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strcpy(mods_statusbar, "\0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ModsApplyActionFunc(void *unused)
|
||||||
|
{
|
||||||
|
if (!M_IsGame(modnames[s_mods_list.curvalue]))
|
||||||
|
{
|
||||||
|
if(Com_ServerState())
|
||||||
|
{
|
||||||
|
// equivalent to "killserver" cmd, but avoids cvar latching below
|
||||||
|
SV_Shutdown("Server is changing games.\n", false);
|
||||||
|
NET_Config(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// called via command buffer so that any running server has time to shutdown
|
||||||
|
Cbuf_AddText(va("game %s\n", modnames[s_mods_list.curvalue]));
|
||||||
|
|
||||||
|
// start the demo cycle in the new game directory
|
||||||
|
Cbuf_AddText("d1\n");
|
||||||
|
|
||||||
|
M_ForceMenuOff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
Mods_MenuInit(void)
|
||||||
|
{
|
||||||
|
int currentmod;
|
||||||
|
|
||||||
|
Mods_NamesInit();
|
||||||
|
|
||||||
|
// pre-select the current mod for display in the list
|
||||||
|
for (currentmod = 0; currentmod < nummods; currentmod++)
|
||||||
|
{
|
||||||
|
if (M_IsGame(modnames[currentmod]))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s_mods_menu.x = (int)(viddef.width * 0.50f);
|
||||||
|
s_mods_menu.nitems = 0;
|
||||||
|
|
||||||
|
s_mods_list.generic.type = MTYPE_SPINCONTROL;
|
||||||
|
s_mods_list.generic.name = "mod";
|
||||||
|
s_mods_list.generic.x = 0;
|
||||||
|
s_mods_list.generic.y = 0;
|
||||||
|
s_mods_list.generic.callback = ModsListFunc;
|
||||||
|
s_mods_list.itemnames = (const char **)modnames;
|
||||||
|
s_mods_list.curvalue = currentmod < nummods ? currentmod : 0;
|
||||||
|
|
||||||
|
s_mods_apply_action.generic.type = MTYPE_ACTION;
|
||||||
|
s_mods_apply_action.generic.flags = QMF_LEFT_JUSTIFY;
|
||||||
|
s_mods_apply_action.generic.name = " apply";
|
||||||
|
s_mods_apply_action.generic.x = 49;
|
||||||
|
s_mods_apply_action.generic.y = 20;
|
||||||
|
s_mods_apply_action.generic.callback = ModsApplyActionFunc;
|
||||||
|
|
||||||
|
Menu_AddItem(&s_mods_menu, (void *)&s_mods_list);
|
||||||
|
Menu_AddItem(&s_mods_menu, (void *)&s_mods_apply_action);
|
||||||
|
|
||||||
|
Menu_Center(&s_mods_menu);
|
||||||
|
|
||||||
|
/* set the original mods statusbar */
|
||||||
|
ModsListFunc(0);
|
||||||
|
Menu_SetStatusBar(&s_mods_menu, mods_statusbar);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
Mods_MenuDraw(void)
|
||||||
|
{
|
||||||
|
Menu_AdjustCursor(&s_mods_menu, 1);
|
||||||
|
Menu_Draw(&s_mods_menu);
|
||||||
|
M_Popup();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
Mods_MenuKey(int key)
|
||||||
|
{
|
||||||
|
return Default_MenuKey(&s_mods_menu, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
M_Menu_Mods_f(void)
|
||||||
|
{
|
||||||
|
Mods_MenuInit();
|
||||||
|
M_PushMenu(Mods_MenuDraw, Mods_MenuKey);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GAME MENU
|
* GAME MENU
|
||||||
*/
|
*/
|
||||||
|
@ -1969,6 +2105,7 @@ static menuaction_s s_hardp_game_action;
|
||||||
static menuaction_s s_load_game_action;
|
static menuaction_s s_load_game_action;
|
||||||
static menuaction_s s_save_game_action;
|
static menuaction_s s_save_game_action;
|
||||||
static menuaction_s s_credits_action;
|
static menuaction_s s_credits_action;
|
||||||
|
static menuaction_s s_mods_action;
|
||||||
static menuseparator_s s_blankline;
|
static menuseparator_s s_blankline;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -2035,9 +2172,17 @@ CreditsFunc(void *unused)
|
||||||
M_Menu_Credits_f();
|
M_Menu_Credits_f();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ModsFunc(void *unused)
|
||||||
|
{
|
||||||
|
M_Menu_Mods_f();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Game_MenuInit(void)
|
Game_MenuInit(void)
|
||||||
{
|
{
|
||||||
|
Mods_NamesInit();
|
||||||
|
|
||||||
s_game_menu.x = (int)(viddef.width * 0.50f);
|
s_game_menu.x = (int)(viddef.width * 0.50f);
|
||||||
s_game_menu.nitems = 0;
|
s_game_menu.nitems = 0;
|
||||||
|
|
||||||
|
@ -2099,9 +2244,21 @@ Game_MenuInit(void)
|
||||||
Menu_AddItem(&s_game_menu, (void *)&s_blankline);
|
Menu_AddItem(&s_game_menu, (void *)&s_blankline);
|
||||||
Menu_AddItem(&s_game_menu, (void *)&s_load_game_action);
|
Menu_AddItem(&s_game_menu, (void *)&s_load_game_action);
|
||||||
Menu_AddItem(&s_game_menu, (void *)&s_save_game_action);
|
Menu_AddItem(&s_game_menu, (void *)&s_save_game_action);
|
||||||
Menu_AddItem(&s_game_menu, (void *)&s_blankline);
|
|
||||||
Menu_AddItem(&s_game_menu, (void *)&s_credits_action);
|
Menu_AddItem(&s_game_menu, (void *)&s_credits_action);
|
||||||
|
|
||||||
|
if(nummods > 1)
|
||||||
|
{
|
||||||
|
s_mods_action.generic.type = MTYPE_ACTION;
|
||||||
|
s_mods_action.generic.flags = QMF_LEFT_JUSTIFY;
|
||||||
|
s_mods_action.generic.x = 0;
|
||||||
|
s_mods_action.generic.y = 90;
|
||||||
|
s_mods_action.generic.name = "mods";
|
||||||
|
s_mods_action.generic.callback = ModsFunc;
|
||||||
|
|
||||||
|
Menu_AddItem(&s_game_menu, (void *)&s_blankline);
|
||||||
|
Menu_AddItem(&s_game_menu, (void *)&s_mods_action);
|
||||||
|
}
|
||||||
|
|
||||||
Menu_Center(&s_game_menu);
|
Menu_Center(&s_game_menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2837,7 +2994,7 @@ M_Menu_JoinServer_f(void)
|
||||||
|
|
||||||
static menuframework_s s_startserver_menu;
|
static menuframework_s s_startserver_menu;
|
||||||
char **mapnames = NULL;
|
char **mapnames = NULL;
|
||||||
static int nummaps;
|
int nummaps;
|
||||||
|
|
||||||
static menuaction_s s_startserver_start_action;
|
static menuaction_s s_startserver_start_action;
|
||||||
static menuaction_s s_startserver_dmoptions_action;
|
static menuaction_s s_startserver_dmoptions_action;
|
||||||
|
@ -4593,6 +4750,7 @@ M_Init(void)
|
||||||
Cmd_AddCommand("menu_playerconfig", M_Menu_PlayerConfig_f);
|
Cmd_AddCommand("menu_playerconfig", M_Menu_PlayerConfig_f);
|
||||||
Cmd_AddCommand("menu_downloadoptions", M_Menu_DownloadOptions_f);
|
Cmd_AddCommand("menu_downloadoptions", M_Menu_DownloadOptions_f);
|
||||||
Cmd_AddCommand("menu_credits", M_Menu_Credits_f);
|
Cmd_AddCommand("menu_credits", M_Menu_Credits_f);
|
||||||
|
Cmd_AddCommand("menu_mods", M_Menu_Mods_f);
|
||||||
Cmd_AddCommand("menu_multiplayer", M_Menu_Multiplayer_f);
|
Cmd_AddCommand("menu_multiplayer", M_Menu_Multiplayer_f);
|
||||||
Cmd_AddCommand("menu_video", M_Menu_Video_f);
|
Cmd_AddCommand("menu_video", M_Menu_Video_f);
|
||||||
Cmd_AddCommand("menu_options", M_Menu_Options_f);
|
Cmd_AddCommand("menu_options", M_Menu_Options_f);
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
|
|
||||||
|
|
||||||
#define MAX_HANDLES 512
|
#define MAX_HANDLES 512
|
||||||
|
#define MAX_MODS 32
|
||||||
#define MAX_PAKS 100
|
#define MAX_PAKS 100
|
||||||
|
|
||||||
#ifdef SYSTEMWIDE
|
#ifdef SYSTEMWIDE
|
||||||
|
@ -1673,9 +1674,18 @@ FS_BuildGameSpecificSearchPath(char *dir)
|
||||||
// are possibly from the new mod dir)
|
// are possibly from the new mod dir)
|
||||||
OGG_InitTrackList();
|
OGG_InitTrackList();
|
||||||
|
|
||||||
// ...and the current list of maps in the "start network server" menu is
|
// ...and the current list of maps in the "start network server" menu is
|
||||||
// cleared so that it will be re-initialized when the menu is accessed
|
// cleared so that it will be re-initialized when the menu is accessed
|
||||||
mapnames = NULL;
|
if (mapnames != NULL)
|
||||||
|
{
|
||||||
|
for (i = 0; i < nummaps; i++)
|
||||||
|
{
|
||||||
|
free(mapnames[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(mapnames);
|
||||||
|
mapnames = NULL;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1792,3 +1802,101 @@ FS_InitFilesystem(void)
|
||||||
Com_Printf("Using '%s' for writing.\n", fs_gamedir);
|
Com_Printf("Using '%s' for writing.\n", fs_gamedir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern int qsort_strcomp(const void *s1, const void *s2);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Combs all Raw search paths to find game dirs containing PAK/PK2/PK3 files.
|
||||||
|
* Returns an alphabetized array of unique relative dir names.
|
||||||
|
*/
|
||||||
|
char**
|
||||||
|
FS_ListMods(int *nummods)
|
||||||
|
{
|
||||||
|
int nmods = 0, numdirchildren, numpacksinchilddir, searchpathlength;
|
||||||
|
char findnamepattern[MAX_OSPATH], modname[MAX_QPATH], searchpath[MAX_OSPATH];
|
||||||
|
char **dirchildren, **packsinchilddir, **modnames;
|
||||||
|
|
||||||
|
modnames = malloc((MAX_QPATH + 1) * (MAX_MODS + 1));
|
||||||
|
memset(modnames, 0, (MAX_QPATH + 1) * (MAX_MODS + 1));
|
||||||
|
|
||||||
|
// iterate over all Raw paths
|
||||||
|
for (fsRawPath_t *search = fs_rawPath; search; search = search->next)
|
||||||
|
{
|
||||||
|
searchpathlength = strlen(search->path);
|
||||||
|
if(!searchpathlength)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure this Raw path ends with a '/' otherwise FS_ListFiles will open its parent dir
|
||||||
|
if(search->path[searchpathlength - 1] != '/')
|
||||||
|
{
|
||||||
|
Com_sprintf(searchpath, sizeof(searchpath), "%s/", search->path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strcpy(searchpath, search->path);
|
||||||
|
}
|
||||||
|
|
||||||
|
dirchildren = FS_ListFiles(searchpath, &numdirchildren, 0, 0);
|
||||||
|
|
||||||
|
// iterate over the children of this Raw path (unless we've already got enough mods)
|
||||||
|
for (int i = 0; i < numdirchildren && nmods < MAX_MODS; i++)
|
||||||
|
{
|
||||||
|
if(dirchildren[i] == NULL)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
numpacksinchilddir = 0;
|
||||||
|
|
||||||
|
// iterate over supported pack types, but ignore ZIP files (they cause false positives)
|
||||||
|
for (int j = 0; j < sizeof(fs_packtypes) / sizeof(fs_packtypes[0]); j++)
|
||||||
|
{
|
||||||
|
if (strcmp("zip", fs_packtypes[j].suffix) != 0)
|
||||||
|
{
|
||||||
|
Com_sprintf(findnamepattern, sizeof(findnamepattern), "%s/*.%s", dirchildren[i], fs_packtypes[j].suffix);
|
||||||
|
|
||||||
|
packsinchilddir = FS_ListFiles(findnamepattern, &numpacksinchilddir, 0, 0);
|
||||||
|
FS_FreeList(packsinchilddir, numpacksinchilddir);
|
||||||
|
|
||||||
|
// if this dir has some pack files, add it if not already in the list
|
||||||
|
if (numpacksinchilddir > 0)
|
||||||
|
{
|
||||||
|
qboolean matchfound = false;
|
||||||
|
|
||||||
|
Com_sprintf(modname, sizeof(modname), "%s", strrchr(dirchildren[i], '/') + 1);
|
||||||
|
|
||||||
|
for (int k = 0; k < nmods; k++)
|
||||||
|
{
|
||||||
|
if (strcmp(modname, modnames[k]) == 0)
|
||||||
|
{
|
||||||
|
matchfound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!matchfound)
|
||||||
|
{
|
||||||
|
modnames[nmods] = malloc(strlen(modname) + 1);
|
||||||
|
strcpy(modnames[nmods], modname);
|
||||||
|
|
||||||
|
nmods++;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FS_FreeList(dirchildren, numdirchildren);
|
||||||
|
}
|
||||||
|
|
||||||
|
modnames[nmods] = 0;
|
||||||
|
|
||||||
|
qsort(modnames, nmods, sizeof(modnames[0]), qsort_strcomp);
|
||||||
|
|
||||||
|
*nummods = nmods;
|
||||||
|
return modnames;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -684,6 +684,7 @@ int FS_LoadFile(char *path, void **buffer);
|
||||||
qboolean FS_FileInGamedir(const char *file);
|
qboolean FS_FileInGamedir(const char *file);
|
||||||
qboolean FS_AddPAKFromGamedir(const char *pak);
|
qboolean FS_AddPAKFromGamedir(const char *pak);
|
||||||
const char* FS_GetNextRawPath(const char* lastRawPath);
|
const char* FS_GetNextRawPath(const char* lastRawPath);
|
||||||
|
char **FS_ListMods(int *nummods);
|
||||||
|
|
||||||
/* a null buffer will just return the file length without loading */
|
/* a null buffer will just return the file length without loading */
|
||||||
/* a -1 length is not present */
|
/* a -1 length is not present */
|
||||||
|
@ -757,6 +758,7 @@ extern char cfgdir[MAX_OSPATH];
|
||||||
/* Hack for working 'game' cmd */
|
/* Hack for working 'game' cmd */
|
||||||
extern char userGivenGame[MAX_QPATH];
|
extern char userGivenGame[MAX_QPATH];
|
||||||
extern char **mapnames;
|
extern char **mapnames;
|
||||||
|
extern int nummaps;
|
||||||
|
|
||||||
extern FILE *log_stats_file;
|
extern FILE *log_stats_file;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue