2016-01-04 14:58:00 -05:00
# include "STDInclude.hpp"
2015-12-23 16:21:03 -05:00
namespace Components
{
2015-12-30 09:37:53 -05:00
std : : vector < std : : string > Menus : : CustomMenus ;
2016-01-14 08:26:29 -05:00
std : : map < std : : string , Game : : menuDef_t * > Menus : : MenuList ;
std : : map < std : : string , Game : : MenuList * > Menus : : MenuListList ;
2015-12-23 21:26:46 -05:00
int Menus : : ReserveSourceHandle ( )
{
// Check if a free slot is available
int i = 1 ;
2016-01-24 13:58:13 -05:00
for ( ; i < MAX_SOURCEFILES ; + + i )
2015-12-23 21:26:46 -05:00
{
if ( ! Game : : sourceFiles [ i ] )
break ;
}
if ( i > = MAX_SOURCEFILES )
return 0 ;
// Reserve it, if yes
Game : : sourceFiles [ i ] = ( Game : : source_t * ) 1 ;
return i ;
}
2016-05-29 10:16:15 -04:00
Game : : script_t * Menus : : LoadMenuScript ( std : : string name , std : : string & buffer )
2015-12-23 21:26:46 -05:00
{
Game : : script_t * script = Game : : Script_Alloc ( sizeof ( Game : : script_t ) + 1 + buffer . length ( ) ) ;
2015-12-28 08:08:46 -05:00
strcpy_s ( script - > filename , sizeof ( script - > filename ) , name . data ( ) ) ;
2016-01-24 06:19:34 -05:00
script - > buffer = reinterpret_cast < char * > ( script + 1 ) ;
2015-12-23 21:26:46 -05:00
2016-01-24 06:19:34 -05:00
* ( script - > buffer + buffer . length ( ) ) = ' \0 ' ;
2015-12-23 21:26:46 -05:00
script - > script_p = script - > buffer ;
script - > lastscript_p = script - > buffer ;
script - > length = buffer . length ( ) ;
script - > end_p = & script - > buffer [ buffer . length ( ) ] ;
script - > line = 1 ;
script - > lastline = 1 ;
script - > tokenavailable = 0 ;
2016-01-24 06:19:34 -05:00
Game : : Script_SetupTokens ( script , reinterpret_cast < char * > ( 0x797F80 ) ) ;
script - > punctuations = reinterpret_cast < Game : : punctuation_t * > ( 0x797F80 ) ;
2015-12-23 21:26:46 -05:00
strcpy ( script - > buffer , buffer . data ( ) ) ;
script - > length = Game : : Script_CleanString ( script - > buffer ) ;
return script ;
}
2016-05-29 10:16:15 -04:00
int Menus : : LoadMenuSource ( std : : string name , std : : string & buffer )
2015-12-23 21:26:46 -05:00
{
int handle = Menus : : ReserveSourceHandle ( ) ;
2015-12-24 06:00:29 -05:00
if ( ! Menus : : IsValidSourceHandle ( handle ) ) return 0 ; // No free source slot!
2015-12-23 21:26:46 -05:00
Game : : source_t * source = nullptr ;
2015-12-24 06:00:29 -05:00
Game : : script_t * script = Menus : : LoadMenuScript ( name , buffer ) ;
2015-12-23 21:26:46 -05:00
if ( ! script )
{
Game : : sourceFiles [ handle ] = nullptr ; // Free reserved slot
return 0 ;
}
script - > next = NULL ;
2016-01-12 13:08:26 -05:00
source = Utils : : Memory : : AllocateArray < Game : : source_t > ( 1 ) ;
2015-12-30 16:22:24 -05:00
if ( ! source )
{
Game : : FreeMemory ( script ) ;
return 0 ;
}
2015-12-23 21:26:46 -05:00
strncpy ( source - > filename , " string " , 64 ) ;
source - > scriptstack = script ;
source - > tokens = NULL ;
source - > defines = NULL ;
source - > indentstack = NULL ;
source - > skip = 0 ;
2016-01-12 13:08:26 -05:00
source - > definehash = ( Game : : define_t * * ) Utils : : Memory : : Allocate ( 4096 ) ;
2015-12-23 21:26:46 -05:00
Game : : sourceFiles [ handle ] = source ;
return handle ;
}
2015-12-24 06:00:29 -05:00
bool Menus : : IsValidSourceHandle ( int handle )
2015-12-23 21:26:46 -05:00
{
2015-12-24 06:00:29 -05:00
return ( handle > 0 & & handle < MAX_SOURCEFILES & & Game : : sourceFiles [ handle ] ) ;
}
int Menus : : KeywordHash ( char * key )
{
2016-03-14 16:29:21 -04:00
int hash = 0 ;
2015-12-24 06:00:29 -05:00
2016-03-14 16:29:21 -04:00
if ( * key )
2015-12-24 06:00:29 -05:00
{
2016-03-14 16:29:21 -04:00
int sub = 3523 - reinterpret_cast < DWORD > ( key ) ;
do
{
char _chr = * key ;
hash + = reinterpret_cast < DWORD > ( & ( key + + ) [ sub ] ) * tolower ( _chr ) ;
} while ( * key ) ;
2015-12-24 06:00:29 -05:00
}
2016-03-14 16:29:21 -04:00
return ( static_cast < uint16_t > ( hash ) + static_cast < uint16_t > ( hash > > 8 ) ) & 0x7F ;
2015-12-24 06:00:29 -05:00
}
2016-01-15 13:39:33 -05:00
Game : : menuDef_t * Menus : : ParseMenu ( int handle )
2015-12-24 06:00:29 -05:00
{
2016-01-12 13:08:26 -05:00
Game : : menuDef_t * menu = Utils : : Memory : : AllocateArray < Game : : menuDef_t > ( 1 ) ;
2015-12-30 16:22:24 -05:00
if ( ! menu ) return nullptr ;
2016-01-12 13:08:26 -05:00
menu - > items = Utils : : Memory : : AllocateArray < Game : : itemDef_t * > ( 512 ) ;
2015-12-30 16:22:24 -05:00
if ( ! menu - > items )
{
2016-01-12 13:08:26 -05:00
Utils : : Memory : : Free ( menu ) ;
2015-12-30 16:22:24 -05:00
return nullptr ;
}
2015-12-24 06:00:29 -05:00
Game : : pc_token_t token ;
2015-12-25 15:42:35 -05:00
if ( ! Game : : PC_ReadTokenHandle ( handle , & token ) | | token . string [ 0 ] ! = ' { ' )
2015-12-24 06:00:29 -05:00
{
2016-01-14 08:26:29 -05:00
Utils : : Memory : : Free ( menu - > items ) ;
Utils : : Memory : : Free ( menu ) ;
return nullptr ;
2015-12-24 06:00:29 -05:00
}
while ( true )
{
ZeroMemory ( & token , sizeof ( token ) ) ;
2015-12-25 15:42:35 -05:00
if ( ! Game : : PC_ReadTokenHandle ( handle , & token ) )
2015-12-24 06:00:29 -05:00
{
Game : : PC_SourceError ( handle , " end of file inside menu \n " ) ;
break ; // Fail
}
if ( * token . string = = ' } ' )
{
break ; // Success
}
int idx = Menus : : KeywordHash ( token . string ) ;
2016-01-24 15:08:14 -05:00
Game : : keywordHash_t * key = Game : : menuParseKeywordHash [ idx ] ;
2015-12-24 06:00:29 -05:00
if ( ! key )
{
Game : : PC_SourceError ( handle , " unknown menu keyword %s " , token . string ) ;
continue ;
}
2015-12-31 07:45:29 -05:00
if ( ! key - > func ( menu , handle ) )
2015-12-24 06:00:29 -05:00
{
Game : : PC_SourceError ( handle , " couldn't parse menu keyword %s " , token . string ) ;
break ; // Fail
}
}
2016-01-16 07:11:00 -05:00
Menus : : OverrideMenu ( menu ) ;
2016-01-15 13:39:33 -05:00
Menus : : RemoveMenu ( menu - > window . name ) ;
Menus : : MenuList [ menu - > window . name ] = menu ;
2016-01-14 08:26:29 -05:00
2015-12-25 15:42:35 -05:00
return menu ;
2015-12-24 06:00:29 -05:00
}
2015-12-28 08:08:46 -05:00
std : : vector < Game : : menuDef_t * > Menus : : LoadMenu ( std : : string menu )
2015-12-24 06:00:29 -05:00
{
std : : vector < Game : : menuDef_t * > menus ;
2015-12-28 08:08:46 -05:00
FileSystem : : File menuFile ( menu ) ;
2015-12-23 21:26:46 -05:00
if ( menuFile . Exists ( ) )
{
2015-12-24 06:00:29 -05:00
Game : : pc_token_t token ;
2015-12-28 08:08:46 -05:00
int handle = Menus : : LoadMenuSource ( menu , menuFile . GetBuffer ( ) ) ;
2015-12-24 06:00:29 -05:00
2015-12-28 08:08:46 -05:00
if ( Menus : : IsValidSourceHandle ( handle ) )
2015-12-24 06:00:29 -05:00
{
2015-12-28 08:08:46 -05:00
while ( true )
2015-12-24 06:00:29 -05:00
{
2015-12-28 08:08:46 -05:00
ZeroMemory ( & token , sizeof ( token ) ) ;
2015-12-24 06:00:29 -05:00
2015-12-28 08:08:46 -05:00
if ( ! Game : : PC_ReadTokenHandle ( handle , & token ) | | token . string [ 0 ] = = ' } ' )
{
break ;
}
2015-12-24 06:00:29 -05:00
2015-12-28 08:08:46 -05:00
if ( ! _stricmp ( token . string , " loadmenu " ) )
{
Game : : PC_ReadTokenHandle ( handle , & token ) ;
2015-12-23 21:26:46 -05:00
2016-01-24 06:19:34 -05:00
Utils : : Merge ( & menus , Menus : : LoadMenu ( Utils : : VA ( " ui_mp \\ %s.menu " , token . string ) ) ) ;
2015-12-28 08:08:46 -05:00
}
2015-12-24 06:00:29 -05:00
2015-12-28 08:08:46 -05:00
if ( ! _stricmp ( token . string , " menudef " ) )
2015-12-24 06:00:29 -05:00
{
2016-01-15 13:39:33 -05:00
Game : : menuDef_t * menudef = Menus : : ParseMenu ( handle ) ;
2015-12-30 16:22:24 -05:00
if ( menudef ) menus . push_back ( menudef ) ;
2015-12-24 06:00:29 -05:00
}
}
2015-12-28 08:08:46 -05:00
Menus : : FreeMenuSource ( handle ) ;
2015-12-24 06:00:29 -05:00
}
2015-12-23 21:26:46 -05:00
}
2015-12-28 08:08:46 -05:00
return menus ;
}
std : : vector < Game : : menuDef_t * > Menus : : LoadMenu ( Game : : menuDef_t * menudef )
{
std : : vector < Game : : menuDef_t * > menus = Menus : : LoadMenu ( Utils : : VA ( " ui_mp \\ %s.menu " , menudef - > window . name ) ) ;
2016-02-12 09:06:06 -05:00
if ( menus . empty ( ) )
2015-12-24 06:00:29 -05:00
{
2016-01-16 07:11:00 -05:00
// Try loading the original menu, if we can't load our custom one
Game : : menuDef_t * originalMenu = AssetHandler : : FindOriginalAsset ( Game : : XAssetType : : ASSET_TYPE_MENU , menudef - > window . name ) . menu ;
if ( originalMenu )
{
menus . push_back ( originalMenu ) ;
}
else
{
menus . push_back ( menudef ) ;
}
2015-12-24 06:00:29 -05:00
}
return menus ;
2015-12-23 21:26:46 -05:00
}
2015-12-28 08:08:46 -05:00
Game : : MenuList * Menus : : LoadScriptMenu ( const char * menu )
{
std : : vector < Game : : menuDef_t * > menus = Menus : : LoadMenu ( menu ) ;
2016-02-12 09:06:06 -05:00
if ( menus . empty ( ) ) return nullptr ;
2015-12-28 08:08:46 -05:00
// Allocate new menu list
2016-01-12 13:08:26 -05:00
Game : : MenuList * newList = Utils : : Memory : : AllocateArray < Game : : MenuList > ( 1 ) ;
2015-12-30 16:22:24 -05:00
if ( ! newList ) return nullptr ;
2016-01-12 13:08:26 -05:00
newList - > menus = Utils : : Memory : : AllocateArray < Game : : menuDef_t * > ( menus . size ( ) ) ;
2015-12-30 16:22:24 -05:00
if ( ! newList - > menus )
{
2016-01-12 13:08:26 -05:00
Utils : : Memory : : Free ( newList ) ;
2015-12-30 16:22:24 -05:00
return nullptr ;
}
2016-01-12 13:08:26 -05:00
newList - > name = Utils : : Memory : : DuplicateString ( menu ) ;
2015-12-28 08:08:46 -05:00
newList - > menuCount = menus . size ( ) ;
// Copy new menus
memcpy ( newList - > menus , menus . data ( ) , menus . size ( ) * sizeof ( Game : : menuDef_t * ) ) ;
2016-01-14 08:26:29 -05:00
Menus : : RemoveMenuList ( newList - > name ) ;
Menus : : MenuListList [ newList - > name ] = newList ;
2015-12-28 08:08:46 -05:00
return newList ;
}
2015-12-23 21:26:46 -05:00
Game : : MenuList * Menus : : LoadMenuList ( Game : : MenuList * menuList )
{
2015-12-24 06:00:29 -05:00
std : : vector < Game : : menuDef_t * > menus ;
2016-01-24 13:58:13 -05:00
for ( int i = 0 ; i < menuList - > menuCount ; + + i )
2015-12-24 06:00:29 -05:00
{
2015-12-25 15:42:35 -05:00
if ( ! menuList - > menus [ i ] )
{
continue ;
}
2016-01-24 06:19:34 -05:00
Utils : : Merge ( & menus , Menus : : LoadMenu ( menuList - > menus [ i ] ) ) ;
2015-12-24 06:00:29 -05:00
}
2015-12-23 21:26:46 -05:00
2015-12-30 09:37:53 -05:00
// Load custom menus
2016-01-08 09:03:38 -05:00
if ( std : : string ( menuList - > name ) = = " ui_mp/code.txt " ) // Should be menus, but code is loaded ingame
2015-12-29 22:19:52 -05:00
{
2015-12-30 09:37:53 -05:00
for ( auto menu : Menus : : CustomMenus )
{
2016-01-24 06:19:34 -05:00
Utils : : Merge ( & menus , Menus : : LoadMenu ( menu ) ) ;
2015-12-30 09:37:53 -05:00
}
2015-12-29 22:19:52 -05:00
}
2015-12-24 06:00:29 -05:00
// Allocate new menu list
2016-01-12 13:08:26 -05:00
Game : : MenuList * newList = Utils : : Memory : : AllocateArray < Game : : MenuList > ( 1 ) ;
2015-12-30 16:22:24 -05:00
if ( ! newList ) return menuList ;
2016-01-16 07:11:00 -05:00
size_t size = menus . size ( ) ;
newList - > menus = Utils : : Memory : : AllocateArray < Game : : menuDef_t * > ( size ) ;
2015-12-30 16:22:24 -05:00
if ( ! newList - > menus )
{
2016-01-12 13:08:26 -05:00
Utils : : Memory : : Free ( newList ) ;
2015-12-30 16:22:24 -05:00
return menuList ;
}
2016-01-12 13:08:26 -05:00
newList - > name = Utils : : Memory : : DuplicateString ( menuList - > name ) ;
2016-01-16 07:11:00 -05:00
newList - > menuCount = size ;
2015-12-23 21:26:46 -05:00
2015-12-24 06:00:29 -05:00
// Copy new menus
2016-01-16 07:11:00 -05:00
memcpy ( newList - > menus , menus . data ( ) , size * sizeof ( Game : : menuDef_t * ) ) ;
2015-12-23 21:26:46 -05:00
2016-01-14 08:26:29 -05:00
Menus : : RemoveMenuList ( newList - > name ) ;
Menus : : MenuListList [ newList - > name ] = newList ;
2015-12-23 21:26:46 -05:00
return newList ;
}
void Menus : : FreeMenuSource ( int handle )
{
2015-12-24 06:00:29 -05:00
if ( ! Menus : : IsValidSourceHandle ( handle ) ) return ;
2015-12-23 21:26:46 -05:00
Game : : source_t * source = Game : : sourceFiles [ handle ] ;
while ( source - > scriptstack )
{
2016-01-24 15:08:14 -05:00
Game : : script_t * script = source - > scriptstack ;
2015-12-23 21:26:46 -05:00
source - > scriptstack = source - > scriptstack - > next ;
2015-12-24 06:53:11 -05:00
Game : : FreeMemory ( script ) ;
}
while ( source - > tokens )
{
2016-01-24 15:08:14 -05:00
Game : : token_t * token = source - > tokens ;
2015-12-24 06:53:11 -05:00
source - > tokens = source - > tokens - > next ;
Game : : FreeMemory ( token ) ;
}
while ( source - > defines )
{
2016-01-24 15:08:14 -05:00
Game : : define_t * define = source - > defines ;
2015-12-24 06:53:11 -05:00
source - > defines = source - > defines - > next ;
Game : : FreeMemory ( define ) ;
2015-12-23 21:26:46 -05:00
}
while ( source - > indentstack )
{
2016-01-24 15:08:14 -05:00
Game : : indent_t * indent = source - > indentstack ;
2015-12-23 21:26:46 -05:00
source - > indentstack = source - > indentstack - > next ;
2016-01-12 13:08:26 -05:00
Utils : : Memory : : Free ( indent ) ;
2015-12-23 21:26:46 -05:00
}
2016-01-12 13:08:26 -05:00
if ( source - > definehash ) Utils : : Memory : : Free ( source - > definehash ) ;
2015-12-23 21:26:46 -05:00
2016-01-12 13:08:26 -05:00
Utils : : Memory : : Free ( source ) ;
2015-12-23 21:26:46 -05:00
Game : : sourceFiles [ handle ] = nullptr ;
}
void Menus : : FreeMenu ( Game : : menuDef_t * menudef )
{
2015-12-24 06:53:11 -05:00
// Do i need to free expressions and strings?
// Or does the game take care of it?
2015-12-24 08:28:08 -05:00
// Seems like it does...
2015-12-24 06:53:11 -05:00
if ( menudef - > items )
{
2015-12-24 08:28:08 -05:00
// Seems like this is obsolete as well,
// as the game handles the memory
2016-01-24 13:58:13 -05:00
//for (int i = 0; i < menudef->itemCount; ++i)
2015-12-24 08:28:08 -05:00
//{
// Game::Menu_FreeItemMemory(menudef->items[i]);
//}
2015-12-24 06:53:11 -05:00
2016-01-12 13:08:26 -05:00
Utils : : Memory : : Free ( menudef - > items ) ;
2015-12-24 06:53:11 -05:00
}
2016-01-12 13:08:26 -05:00
Utils : : Memory : : Free ( menudef ) ;
2015-12-23 21:26:46 -05:00
}
void Menus : : FreeMenuList ( Game : : MenuList * menuList )
{
2015-12-30 16:22:24 -05:00
if ( ! menuList ) return ;
2015-12-23 21:26:46 -05:00
2015-12-30 16:22:24 -05:00
// Keep our compiler happy
Game : : MenuList list = { menuList - > name , menuList - > menuCount , menuList - > menus } ;
if ( list . name )
{
2016-01-12 13:08:26 -05:00
Utils : : Memory : : Free ( list . name ) ;
2015-12-30 16:22:24 -05:00
}
2015-12-23 21:26:46 -05:00
2015-12-30 16:22:24 -05:00
if ( list . menus )
{
2016-01-12 13:08:26 -05:00
Utils : : Memory : : Free ( list . menus ) ;
2015-12-23 21:26:46 -05:00
}
2015-12-30 16:22:24 -05:00
2016-01-12 13:08:26 -05:00
Utils : : Memory : : Free ( menuList ) ;
2015-12-23 21:26:46 -05:00
}
2016-01-14 08:26:29 -05:00
void Menus : : RemoveMenu ( std : : string menu )
{
auto i = Menus : : MenuList . find ( menu ) ;
if ( i ! = Menus : : MenuList . end ( ) )
{
if ( i - > second ) Menus : : FreeMenu ( i - > second ) ;
2016-06-04 15:24:03 -04:00
i = Menus : : MenuList . erase ( i ) ;
2016-01-14 08:26:29 -05:00
}
}
2015-12-24 08:28:08 -05:00
void Menus : : RemoveMenu ( Game : : menuDef_t * menudef )
{
2016-01-24 13:58:13 -05:00
for ( auto i = Menus : : MenuList . begin ( ) ; i ! = Menus : : MenuList . end ( ) ; + + i )
2015-12-24 08:28:08 -05:00
{
2016-01-14 08:26:29 -05:00
if ( i - > second = = menudef )
2015-12-24 08:28:08 -05:00
{
Menus : : FreeMenu ( menudef ) ;
2016-06-04 15:24:03 -04:00
i = Menus : : MenuList . erase ( i ) ;
2015-12-24 08:28:08 -05:00
break ;
}
}
}
2016-01-14 08:26:29 -05:00
void Menus : : RemoveMenuList ( std : : string menuList )
2015-12-24 08:28:08 -05:00
{
2016-01-14 08:26:29 -05:00
auto i = Menus : : MenuListList . find ( menuList ) ;
if ( i ! = Menus : : MenuListList . end ( ) )
2015-12-24 08:28:08 -05:00
{
2016-01-14 08:26:29 -05:00
if ( i - > second )
2015-12-24 08:28:08 -05:00
{
2016-01-24 13:58:13 -05:00
for ( auto j = 0 ; j < i - > second - > menuCount ; + + j )
2015-12-24 08:28:08 -05:00
{
2016-01-14 08:26:29 -05:00
Menus : : RemoveMenu ( i - > second - > menus [ j ] ) ;
2015-12-24 08:28:08 -05:00
}
2016-01-14 08:26:29 -05:00
Menus : : FreeMenuList ( i - > second ) ;
2015-12-24 08:28:08 -05:00
}
2016-01-14 08:26:29 -05:00
2016-06-04 15:24:03 -04:00
i = Menus : : MenuListList . erase ( i ) ;
2015-12-24 08:28:08 -05:00
}
}
2016-01-16 07:11:00 -05:00
// This is actually a really important function
// It checks if we have already loaded the menu we passed and replaces its instances in memory
// Due to deallocating the old menu, the game might crash on not being able to handle its old instance
// So we need to override it in our menu lists and the game's ui context
// EDIT: We might also remove the old instances inside RemoveMenu
// EDIT2: Removing old instances without having a menu to replace them with might leave a nullptr
2016-01-16 07:25:39 -05:00
// EDIT3: Wouldn't it be better to check if the new menu we're trying to load has already been loaded and not was not deallocated and return that one instead of loading a new one?
2016-01-16 07:11:00 -05:00
void Menus : : OverrideMenu ( Game : : menuDef_t * menu )
{
if ( ! menu | | ! menu - > window . name ) return ;
std : : string name = menu - > window . name ;
// Find the old menu
auto i = Menus : : MenuList . find ( name ) ;
if ( i ! = Menus : : MenuList . end ( ) )
{
// We have found it, *yay*
Game : : menuDef_t * oldMenu = i - > second ;
// Replace every old instance with our new one in the ui context
2016-01-24 13:58:13 -05:00
for ( int j = 0 ; j < Game : : uiContext - > menuCount ; + + j )
2016-01-16 07:11:00 -05:00
{
2016-01-24 06:19:34 -05:00
if ( Game : : uiContext - > menus [ j ] = = oldMenu )
2016-01-16 07:11:00 -05:00
{
2016-01-24 06:19:34 -05:00
Game : : uiContext - > menus [ j ] = menu ;
2016-01-16 07:11:00 -05:00
}
}
// Replace every old instance with our new one in our menu lists
2016-01-24 13:58:13 -05:00
for ( auto j = Menus : : MenuListList . begin ( ) ; j ! = Menus : : MenuListList . end ( ) ; + + j )
2016-01-16 07:11:00 -05:00
{
2016-01-24 06:19:34 -05:00
Game : : MenuList * list = j - > second ;
2016-01-16 07:11:00 -05:00
if ( list & & list - > menus )
{
2016-01-24 13:58:13 -05:00
for ( int k = 0 ; k < list - > menuCount ; + + k )
2016-01-16 07:11:00 -05:00
{
2016-01-24 06:19:34 -05:00
if ( list - > menus [ k ] = = oldMenu )
2016-01-16 07:11:00 -05:00
{
2016-01-24 06:19:34 -05:00
list - > menus [ k ] = menu ;
2016-01-16 07:11:00 -05:00
}
}
}
}
}
}
2016-01-14 08:26:29 -05:00
void Menus : : RemoveMenuList ( Game : : MenuList * menuList )
{
if ( ! menuList | | ! menuList - > name ) return ;
Menus : : RemoveMenuList ( menuList - > name ) ;
}
2015-12-23 21:26:46 -05:00
void Menus : : FreeEverything ( )
{
2016-01-24 13:58:13 -05:00
for ( auto i = Menus : : MenuListList . begin ( ) ; i ! = Menus : : MenuListList . end ( ) ; + + i )
2016-01-14 08:26:29 -05:00
{
Menus : : FreeMenuList ( i - > second ) ;
}
Menus : : MenuListList . clear ( ) ;
2016-01-24 13:58:13 -05:00
for ( auto i = Menus : : MenuList . begin ( ) ; i ! = Menus : : MenuList . end ( ) ; + + i )
2015-12-23 21:26:46 -05:00
{
2016-01-14 08:26:29 -05:00
Menus : : FreeMenu ( i - > second ) ;
2015-12-23 21:26:46 -05:00
}
Menus : : MenuList . clear ( ) ;
2016-01-14 08:26:29 -05:00
}
2016-02-06 07:37:23 -05:00
Game : : XAssetHeader Menus : : MenuLoad ( Game : : XAssetType type , std : : string filename )
2016-01-14 08:26:29 -05:00
{
2016-02-06 07:37:23 -05:00
return { Game : : Menus_FindByName ( Game : : uiContext , filename . data ( ) ) } ;
2015-12-23 21:26:46 -05:00
}
2016-02-06 07:37:23 -05:00
Game : : XAssetHeader Menus : : MenuFileLoad ( Game : : XAssetType type , std : : string filename )
2015-12-23 21:26:46 -05:00
{
2015-12-25 15:42:35 -05:00
Game : : XAssetHeader header = { 0 } ;
2015-12-23 21:26:46 -05:00
2016-02-06 07:37:23 -05:00
Game : : MenuList * menuList = Game : : DB_FindXAssetHeader ( type , filename . data ( ) ) . menuList ;
2015-12-23 21:26:46 -05:00
header . menuList = menuList ;
2016-01-15 13:23:07 -05:00
2016-01-15 13:39:33 -05:00
// Free the last menulist and ui context, as we have to rebuild it with the new menus
if ( Menus : : MenuListList . find ( filename ) ! = Menus : : MenuListList . end ( ) )
{
Game : : MenuList * list = Menus : : MenuListList [ filename ] ;
2016-01-24 13:58:13 -05:00
for ( int i = 0 ; list & & list - > menus & & i < list - > menuCount ; + + i )
2016-01-15 13:39:33 -05:00
{
Menus : : RemoveMenuFromContext ( Game : : uiContext , list - > menus [ i ] ) ;
}
Menus : : RemoveMenuList ( filename ) ;
}
2015-12-23 21:26:46 -05:00
if ( menuList )
{
2015-12-28 08:08:46 -05:00
// Parse scriptmenus!
if ( ! strcmp ( menuList - > menus [ 0 ] - > window . name , " default_menu " ) | | Utils : : EndsWith ( filename , " .menu " ) )
{
if ( FileSystem : : File ( filename ) . Exists ( ) )
{
2016-02-06 07:37:23 -05:00
header . menuList = Menus : : LoadScriptMenu ( filename . data ( ) ) ;
2015-12-28 08:08:46 -05:00
// Reset, if we didn't find scriptmenus
if ( ! header . menuList )
{
header . menuList = menuList ;
}
}
}
else
2015-12-24 08:28:08 -05:00
{
header . menuList = Menus : : LoadMenuList ( menuList ) ;
}
2015-12-23 21:26:46 -05:00
}
return header ;
}
2016-01-15 13:23:07 -05:00
bool Menus : : IsMenuVisible ( Game : : UiContext * dc , Game : : menuDef_t * menu )
2016-01-14 17:23:14 -05:00
{
2016-01-15 13:23:07 -05:00
std : : string _connect = " connect " ;
2016-01-14 17:23:14 -05:00
2016-01-15 13:23:07 -05:00
if ( menu & & menu - > window . name )
2016-01-14 18:20:37 -05:00
{
2016-01-15 13:23:07 -05:00
if ( menu - > window . name = = _connect ) // Check if we're supposed to draw the loadscreen
2016-01-14 18:20:37 -05:00
{
2016-01-15 13:23:07 -05:00
Game : : menuDef_t * originalConnect = AssetHandler : : FindOriginalAsset ( Game : : XAssetType : : ASSET_TYPE_MENU , " connect " ) . menu ;
2016-01-14 18:20:37 -05:00
2016-01-15 13:23:07 -05:00
if ( originalConnect = = menu ) // Check if we draw the original loadscreen
2016-01-14 18:20:37 -05:00
{
2016-01-15 13:39:33 -05:00
if ( Menus : : MenuList . find ( " connect " ) ! = Menus : : MenuList . end ( ) ) // Check if we have a custom loadscreen, to prevent drawing the original one ontop
2016-01-15 13:23:07 -05:00
{
2016-01-15 13:39:33 -05:00
return false ;
2016-01-15 13:23:07 -05:00
}
2016-01-14 18:20:37 -05:00
}
}
}
2016-01-15 13:23:07 -05:00
return Game : : Menu_IsVisible ( dc , menu ) ;
2016-01-14 18:20:37 -05:00
}
2016-01-15 13:23:07 -05:00
void Menus : : RemoveMenuFromContext ( Game : : UiContext * dc , Game : : menuDef_t * menu )
2015-12-25 16:34:05 -05:00
{
2016-01-15 13:23:07 -05:00
// Search menu in context
int i = 0 ;
2016-01-24 13:58:13 -05:00
for ( ; i < dc - > menuCount ; + + i )
2015-12-25 16:34:05 -05:00
{
2016-01-15 13:23:07 -05:00
if ( dc - > menus [ i ] = = menu )
2015-12-25 16:34:05 -05:00
{
2016-01-15 13:23:07 -05:00
break ;
2015-12-25 16:34:05 -05:00
}
}
2016-01-15 13:23:07 -05:00
// Remove from stack
if ( i < dc - > menuCount )
2016-01-14 09:29:39 -05:00
{
2016-01-24 13:58:13 -05:00
for ( ; i < dc - > menuCount - 1 ; + + i )
2016-01-14 09:29:39 -05:00
{
2016-01-15 13:23:07 -05:00
dc - > menus [ i ] = dc - > menus [ i + 1 ] ;
2016-01-14 09:29:39 -05:00
}
2016-01-14 17:23:14 -05:00
2016-01-15 13:23:07 -05:00
// Clear last menu
dc - > menus [ - - dc - > menuCount ] = 0 ;
2016-01-14 09:29:39 -05:00
}
2016-01-14 17:23:14 -05:00
}
2016-01-14 09:29:39 -05:00
2015-12-30 09:37:53 -05:00
void Menus : : Add ( std : : string menu )
{
Menus : : CustomMenus . push_back ( menu ) ;
}
2015-12-23 16:21:03 -05:00
Menus : : Menus ( )
{
2015-12-29 18:13:12 -05:00
if ( Dedicated : : IsDedicated ( ) ) return ;
2016-01-14 08:26:29 -05:00
// Ensure everything is zero'ed
Menus : : FreeEverything ( ) ;
// Intercept asset finding
AssetHandler : : OnFind ( Game : : XAssetType : : ASSET_TYPE_MENU , Menus : : MenuLoad ) ;
2015-12-26 08:27:34 -05:00
AssetHandler : : OnFind ( Game : : XAssetType : : ASSET_TYPE_MENUFILE , Menus : : MenuFileLoad ) ;
2015-12-23 21:26:46 -05:00
2016-01-14 09:29:39 -05:00
// Don't open connect menu
Utils : : Hook : : Nop ( 0x428E48 , 5 ) ;
// Intercept menu painting
Utils : : Hook ( 0x4FFBDF , Menus : : IsMenuVisible , HOOK_CALL ) . Install ( ) - > Quick ( ) ;
2015-12-24 06:00:29 -05:00
// disable the 2 new tokens in ItemParse_rect
Utils : : Hook : : Set < BYTE > ( 0x640693 , 0xEB ) ;
// don't load ASSET_TYPE_MENU assets for every menu (might cause patch menus to fail)
Utils : : Hook : : Nop ( 0x453406 , 5 ) ;
2015-12-25 15:42:35 -05:00
//make Com_Error and similar go back to main_text instead of menu_xboxlive.
2015-12-30 16:22:24 -05:00
Utils : : Hook : : SetString ( 0x6FC790 , " main_text " ) ;
2015-12-25 15:42:35 -05:00
2015-12-23 16:21:03 -05:00
Command : : Add ( " openmenu " , [ ] ( Command : : Params params )
{
if ( params . Length ( ) ! = 2 )
{
Logger : : Print ( " USAGE: openmenu <menu name> \n " ) ;
return ;
}
2015-12-25 16:34:05 -05:00
Game : : Menus_OpenByName ( Game : : uiContext , params [ 1 ] ) ;
2015-12-23 21:26:46 -05:00
} ) ;
2015-12-23 16:21:03 -05:00
2015-12-23 21:26:46 -05:00
Command : : Add ( " reloadmenus " , [ ] ( Command : : Params params )
{
2015-12-24 06:30:52 -05:00
// Close all menus
2015-12-25 16:34:05 -05:00
Game : : Menus_CloseAll ( Game : : uiContext ) ;
2015-12-24 06:30:52 -05:00
// Free custom menus
2015-12-23 21:26:46 -05:00
Menus : : FreeEverything ( ) ;
2015-12-24 06:30:52 -05:00
2015-12-24 08:28:08 -05:00
// Only disconnect if in-game, context is updated automatically!
if ( Game : : CL_IsCgameInitialized ( ) )
{
Game : : Cbuf_AddText ( 0 , " disconnect \n " ) ;
}
else
{
// Reinitialize ui context
2016-01-16 07:11:00 -05:00
Utils : : Hook : : Call < void ( ) > ( 0x401700 ) ( ) ;
2015-12-24 06:30:52 -05:00
2015-12-24 08:28:08 -05:00
// Reopen main menu
2015-12-25 16:34:05 -05:00
Game : : Menus_OpenByName ( Game : : uiContext , " main_text " ) ;
2015-12-24 08:28:08 -05:00
}
2015-12-23 16:21:03 -05:00
} ) ;
2015-12-30 09:37:53 -05:00
// Define custom menus here
Menus : : Add ( " ui_mp/theater_menu.menu " ) ;
Menus : : Add ( " ui_mp/pc_options_multi.menu " ) ;
2016-01-10 07:25:09 -05:00
Menus : : Add ( " ui_mp/pc_options_game.menu " ) ;
2016-01-27 16:42:52 -05:00
Menus : : Add ( " ui_mp/stats_reset.menu " ) ;
Menus : : Add ( " ui_mp/stats_unlock.menu " ) ;
2016-02-22 18:31:28 -05:00
Menus : : Add ( " ui_mp/security_increase_popmenu.menu " ) ;
2015-12-23 16:21:03 -05:00
}
2015-12-23 21:26:46 -05:00
Menus : : ~ Menus ( )
{
2015-12-30 09:37:53 -05:00
Menus : : CustomMenus . clear ( ) ;
2015-12-23 21:26:46 -05:00
Menus : : FreeEverything ( ) ;
}
2015-12-23 16:21:03 -05:00
}