2003-02-16 04:01:45 +00:00
|
|
|
#include "global.h"
|
2003-02-06 07:32:57 +00:00
|
|
|
/*
|
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
Class: NoteSkinManager
|
|
|
|
|
|
|
|
|
|
Desc: See header.
|
|
|
|
|
|
|
|
|
|
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
|
|
|
|
|
Chris Danford
|
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "NoteSkinManager.h"
|
|
|
|
|
#include "RageLog.h"
|
|
|
|
|
#include "RageException.h"
|
|
|
|
|
#include "GameState.h"
|
|
|
|
|
#include "GameDef.h"
|
|
|
|
|
#include "StyleInput.h"
|
|
|
|
|
#include "StyleDef.h"
|
|
|
|
|
#include "RageUtil.h"
|
|
|
|
|
#include "GameManager.h"
|
2003-07-22 07:47:27 +00:00
|
|
|
#include "arch/arch.h"
|
2003-09-03 04:30:29 +00:00
|
|
|
#include "RageDisplay.h"
|
|
|
|
|
#include "arch/ArchHooks/ArchHooks.h"
|
2003-02-06 07:32:57 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
NoteSkinManager* NOTESKIN = NULL; // global object accessable from anywhere in the program
|
|
|
|
|
|
|
|
|
|
|
2003-07-22 07:47:27 +00:00
|
|
|
const CString NOTESKINS_DIR = BASE_PATH "NoteSkins" SLASH;
|
2003-08-15 03:14:53 +00:00
|
|
|
const CString GAME_BASE_NOTESKIN_NAME = "default";
|
|
|
|
|
const CString GLOBAL_BASE_NOTESKIN_DIR = NOTESKINS_DIR + "common" SLASH "default" SLASH;
|
2003-02-06 07:32:57 +00:00
|
|
|
|
|
|
|
|
NoteSkinManager::NoteSkinManager()
|
|
|
|
|
{
|
2003-09-12 04:18:43 +00:00
|
|
|
m_CurGame = GAME_INVALID;
|
2003-02-06 07:32:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NoteSkinManager::~NoteSkinManager()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-22 04:54:04 +00:00
|
|
|
void NoteSkinManager::RefreshNoteSkinData( Game game )
|
2003-02-06 07:32:57 +00:00
|
|
|
{
|
2003-09-12 04:18:43 +00:00
|
|
|
/* Reload even if we don't need to, so exiting out of the menus refreshes the note
|
|
|
|
|
* skin list (so you don't have to restart to see new noteskins). */
|
|
|
|
|
m_CurGame = GAMESTATE->m_CurGame;
|
|
|
|
|
|
2003-06-04 20:06:10 +00:00
|
|
|
GameDef* pGameDef = GAMEMAN->GetGameDefForGame( game );
|
2003-02-06 07:32:57 +00:00
|
|
|
|
2003-07-22 07:47:27 +00:00
|
|
|
CString sBaseSkinFolder = NOTESKINS_DIR + pGameDef->m_szName + SLASH;
|
2003-04-22 04:54:04 +00:00
|
|
|
CStringArray asNoteSkinNames;
|
|
|
|
|
GetDirListing( sBaseSkinFolder + "*", asNoteSkinNames, true );
|
2003-02-06 07:32:57 +00:00
|
|
|
|
2003-04-22 04:54:04 +00:00
|
|
|
// strip out "CVS"
|
2003-04-23 02:45:51 +00:00
|
|
|
for( int i=asNoteSkinNames.size()-1; i>=0; i-- )
|
2003-04-22 04:54:04 +00:00
|
|
|
if( 0 == stricmp("cvs", asNoteSkinNames[i]) )
|
|
|
|
|
asNoteSkinNames.erase( asNoteSkinNames.begin()+i, asNoteSkinNames.begin()+i+1 );
|
2003-02-06 07:32:57 +00:00
|
|
|
|
2003-04-22 04:54:04 +00:00
|
|
|
m_mapNameToData.clear();
|
2003-04-23 02:45:51 +00:00
|
|
|
for( unsigned j=0; j<asNoteSkinNames.size(); j++ )
|
2003-02-06 07:32:57 +00:00
|
|
|
{
|
2003-04-23 02:45:51 +00:00
|
|
|
CString sName = asNoteSkinNames[j];
|
2003-04-22 04:54:04 +00:00
|
|
|
sName.MakeLower();
|
|
|
|
|
m_mapNameToData[sName] = NoteSkinData();
|
|
|
|
|
LoadNoteSkinData( sName, m_mapNameToData[sName] );
|
2003-02-06 07:32:57 +00:00
|
|
|
}
|
2003-04-22 04:54:04 +00:00
|
|
|
}
|
2003-02-06 07:32:57 +00:00
|
|
|
|
2003-04-22 04:54:04 +00:00
|
|
|
void NoteSkinManager::LoadNoteSkinData( CString sNoteSkinName, NoteSkinData& data_out )
|
|
|
|
|
{
|
|
|
|
|
data_out.sName = sNoteSkinName;
|
|
|
|
|
data_out.metrics.Reset();
|
2003-02-09 00:47:11 +00:00
|
|
|
|
2003-08-15 03:14:53 +00:00
|
|
|
///* Read only the default keys from the default noteskin. */
|
|
|
|
|
//IniFile defaults;
|
|
|
|
|
//defaults.SetPath( GLOBAL_BASE_NOTESKIN_DIR+"metrics.ini" );
|
|
|
|
|
//defaults.ReadFile();
|
|
|
|
|
//defaults.SetPath( GetNoteSkinDir(BASE_NOTESKIN_NAME)+"metrics.ini" );
|
|
|
|
|
//defaults.ReadFile();
|
2003-02-09 00:47:11 +00:00
|
|
|
|
2003-08-15 03:14:53 +00:00
|
|
|
// Why only use NoteDisplay? Now, a few different classes take
|
|
|
|
|
// metrics from the NoteSkin. -Chris
|
|
|
|
|
//const IniFile::key *def = defaults.GetKey("NoteDisplay");
|
|
|
|
|
//if(def)
|
|
|
|
|
// data_out.metrics.SetValue("NoteDisplay", *def);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Load global NoteSkin defaults */
|
|
|
|
|
data_out.metrics.SetPath( GLOBAL_BASE_NOTESKIN_DIR+"metrics.ini" );
|
|
|
|
|
data_out.metrics.ReadFile();
|
|
|
|
|
|
|
|
|
|
/* Load game NoteSkin defaults */
|
|
|
|
|
data_out.metrics.SetPath( GetNoteSkinDir(GAME_BASE_NOTESKIN_NAME)+"metrics.ini" );
|
|
|
|
|
data_out.metrics.ReadFile();
|
|
|
|
|
|
|
|
|
|
/* Read the active NoteSkin */
|
2003-04-22 04:54:04 +00:00
|
|
|
data_out.metrics.SetPath( GetNoteSkinDir(sNoteSkinName)+"metrics.ini" );
|
|
|
|
|
data_out.metrics.ReadFile();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void NoteSkinManager::GetNoteSkinNames( CStringArray &AddTo )
|
|
|
|
|
{
|
2003-09-12 04:18:43 +00:00
|
|
|
/* If the skin data for the current game isn't already load it, load it now. */
|
|
|
|
|
if( m_CurGame != GAMESTATE->m_CurGame )
|
|
|
|
|
RefreshNoteSkinData( GAMESTATE->m_CurGame );
|
|
|
|
|
|
|
|
|
|
/* Don't call GetNoteSkinNames below, since we don't want to call RefreshNoteSkinData; it's
|
|
|
|
|
* slow. */
|
|
|
|
|
for( map<CString,NoteSkinData>::const_iterator iter = m_mapNameToData.begin();
|
|
|
|
|
iter != m_mapNameToData.end(); ++iter )
|
|
|
|
|
{
|
|
|
|
|
AddTo.push_back( iter->second.sName );
|
|
|
|
|
}
|
2003-04-22 04:54:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NoteSkinManager::GetNoteSkinNames( Game game, CStringArray &AddTo )
|
|
|
|
|
{
|
2003-06-04 20:06:10 +00:00
|
|
|
RefreshNoteSkinData( game );
|
2003-04-22 04:54:04 +00:00
|
|
|
|
|
|
|
|
for( map<CString,NoteSkinData>::const_iterator iter = m_mapNameToData.begin();
|
2003-09-12 04:18:43 +00:00
|
|
|
iter != m_mapNameToData.end(); ++iter )
|
2003-04-22 04:54:04 +00:00
|
|
|
{
|
|
|
|
|
AddTo.push_back( iter->second.sName );
|
|
|
|
|
}
|
2003-06-04 20:06:10 +00:00
|
|
|
|
|
|
|
|
/* Put the note skins back. */
|
|
|
|
|
RefreshNoteSkinData( GAMESTATE->m_CurGame );
|
2003-04-22 04:54:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool NoteSkinManager::DoesNoteSkinExist( CString sSkinName )
|
|
|
|
|
{
|
|
|
|
|
CStringArray asSkinNames;
|
|
|
|
|
GetNoteSkinNames( asSkinNames );
|
|
|
|
|
for( unsigned i=0; i<asSkinNames.size(); i++ )
|
|
|
|
|
if( 0==stricmp(sSkinName, asSkinNames[i]) )
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
2003-02-06 07:32:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CString NoteSkinManager::GetNoteSkinDir( CString sSkinName )
|
|
|
|
|
{
|
2003-08-15 03:14:53 +00:00
|
|
|
CString sGame = GAMESTATE->GetCurrentGameDef()->m_szName;
|
2003-02-06 07:32:57 +00:00
|
|
|
|
2003-08-15 03:14:53 +00:00
|
|
|
return NOTESKINS_DIR + sGame + SLASH + sSkinName + SLASH;
|
2003-02-06 07:32:57 +00:00
|
|
|
}
|
|
|
|
|
|
2003-09-12 04:08:03 +00:00
|
|
|
CString NoteSkinManager::GetMetric( CString sNoteSkinName, CString sButtonName, CString sValue )
|
2003-02-06 07:32:57 +00:00
|
|
|
{
|
2003-09-12 04:44:53 +00:00
|
|
|
sNoteSkinName.MakeLower();
|
2003-02-06 07:32:57 +00:00
|
|
|
CString sReturn;
|
2003-04-22 04:54:04 +00:00
|
|
|
NoteSkinData& data = m_mapNameToData[sNoteSkinName];
|
|
|
|
|
if( data.metrics.GetValue( sButtonName, sValue, sReturn ) )
|
2003-02-08 23:47:47 +00:00
|
|
|
return sReturn;
|
2003-04-22 04:54:04 +00:00
|
|
|
if( !data.metrics.GetValue( "NoteDisplay", sValue, sReturn ) )
|
2003-08-10 08:58:11 +00:00
|
|
|
RageException::Throw( "Could not read metric '[%s] %s' or '[NoteDisplay] %s' in '%s'",
|
2003-07-20 21:23:20 +00:00
|
|
|
sButtonName.c_str(), sValue.c_str(), sValue.c_str(), sNoteSkinName.c_str() );
|
2003-02-06 07:32:57 +00:00
|
|
|
return sReturn;
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-12 04:08:03 +00:00
|
|
|
int NoteSkinManager::GetMetricI( CString sNoteSkinName, CString sButtonName, CString sValueName )
|
|
|
|
|
{
|
|
|
|
|
return atoi( GetMetric(sNoteSkinName,sButtonName,sValueName) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float NoteSkinManager::GetMetricF( CString sNoteSkinName, CString sButtonName, CString sValueName )
|
|
|
|
|
{
|
|
|
|
|
return (float)atof( GetMetric(sNoteSkinName,sButtonName,sValueName) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool NoteSkinManager::GetMetricB( CString sNoteSkinName, CString sButtonName, CString sValueName )
|
|
|
|
|
{
|
|
|
|
|
return atoi( GetMetric(sNoteSkinName,sButtonName,sValueName) ) != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RageColor NoteSkinManager::GetMetricC( CString sNoteSkinName, CString sButtonName, CString sValueName )
|
|
|
|
|
{
|
|
|
|
|
float r=1,b=1,g=1,a=1; // initialize in case sscanf fails
|
|
|
|
|
CString sValue = GetMetric(sNoteSkinName,sButtonName,sValueName);
|
|
|
|
|
char szValue[40];
|
|
|
|
|
strncpy( szValue, sValue, 39 );
|
|
|
|
|
int result = sscanf( szValue, "%f,%f,%f,%f", &r, &g, &b, &a );
|
|
|
|
|
if( result != 4 )
|
|
|
|
|
{
|
|
|
|
|
LOG->Warn( "The color value '%s' for theme metric '%s : %s' is invalid.", szValue, sButtonName.c_str(), sValueName.c_str() );
|
|
|
|
|
ASSERT(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return RageColor(r,g,b,a);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-02-08 23:47:47 +00:00
|
|
|
CString NoteSkinManager::ColToButtonName(int col)
|
2003-02-06 07:32:57 +00:00
|
|
|
{
|
|
|
|
|
const StyleDef* pStyleDef = GAMESTATE->GetCurrentStyleDef();
|
|
|
|
|
const GameDef* pGameDef = GAMESTATE->GetCurrentGameDef();
|
|
|
|
|
|
|
|
|
|
StyleInput SI( PLAYER_1, col );
|
|
|
|
|
GameInput GI = pStyleDef->StyleInputToGameInput( SI );
|
2003-02-08 23:47:47 +00:00
|
|
|
return pGameDef->m_szButtonNames[GI.button];
|
|
|
|
|
}
|
2003-02-06 07:32:57 +00:00
|
|
|
|
2003-04-17 21:45:37 +00:00
|
|
|
CString NoteSkinManager::GetPathTo( PlayerNumber pn, int col, CString sFileName )
|
2003-02-08 23:47:47 +00:00
|
|
|
{
|
|
|
|
|
CString sButtonName = ColToButtonName(col);
|
2003-02-06 07:32:57 +00:00
|
|
|
|
2003-04-17 21:45:37 +00:00
|
|
|
return GetPathTo( pn, sButtonName, sFileName );
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-12 04:08:03 +00:00
|
|
|
|
2003-04-17 21:45:37 +00:00
|
|
|
CString NoteSkinManager::GetPathTo( PlayerNumber pn, CString sButtonName, CString sFileName ) // looks in GAMESTATE for the current Style
|
|
|
|
|
{
|
2003-08-15 03:14:53 +00:00
|
|
|
// search active NoteSkin
|
2003-04-22 04:54:04 +00:00
|
|
|
CString sNoteSkinName = GAMESTATE->m_PlayerOptions[pn].m_sNoteSkin;
|
|
|
|
|
sNoteSkinName.MakeLower();
|
2003-09-12 04:08:03 +00:00
|
|
|
return GetPathTo( sNoteSkinName, sButtonName, sFileName );
|
|
|
|
|
}
|
2003-02-06 07:32:57 +00:00
|
|
|
|
2003-09-12 04:08:03 +00:00
|
|
|
CString NoteSkinManager::GetPathTo( CString NoteSkin, CString sButtonName, CString sFileName )
|
|
|
|
|
{
|
|
|
|
|
CString ret = GetPathTo( GetNoteSkinDir(NoteSkin), sButtonName+" "+sFileName );
|
2003-02-06 07:32:57 +00:00
|
|
|
if( !ret.empty() ) // we found something
|
|
|
|
|
return ret;
|
|
|
|
|
|
2003-08-15 03:14:53 +00:00
|
|
|
// Search game default NoteSkin
|
2003-09-03 04:30:29 +00:00
|
|
|
ret = GetPathTo( GetNoteSkinDir(GAME_BASE_NOTESKIN_NAME), sButtonName+" "+sFileName);
|
2003-08-15 03:14:53 +00:00
|
|
|
if( !ret.empty() ) // we found something
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
// Search global default NoteSkin
|
2003-09-03 04:30:29 +00:00
|
|
|
ret = GetPathTo( GLOBAL_BASE_NOTESKIN_DIR, "Fallback "+sFileName );
|
2003-08-15 03:14:53 +00:00
|
|
|
if( !ret.empty() ) // we found something
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
RageException::Throw( "The NoteSkin element '%s %s' could not be found in '%s', '%s', or '%s'.",
|
2003-04-25 00:01:35 +00:00
|
|
|
sButtonName.c_str(), sFileName.c_str(),
|
2003-09-12 04:08:03 +00:00
|
|
|
GetNoteSkinDir(NoteSkin).c_str(),
|
2003-08-15 03:14:53 +00:00
|
|
|
GetNoteSkinDir(GAME_BASE_NOTESKIN_NAME).c_str(),
|
2003-09-14 20:01:53 +00:00
|
|
|
GLOBAL_BASE_NOTESKIN_DIR.c_str() );
|
2003-02-06 07:32:57 +00:00
|
|
|
}
|
|
|
|
|
|
2003-09-03 04:30:29 +00:00
|
|
|
CString NoteSkinManager::GetPathTo( CString sDir, CString sFileName )
|
2003-02-06 07:32:57 +00:00
|
|
|
{
|
2003-09-03 04:30:29 +00:00
|
|
|
CStringArray matches; // fill this with the possible files
|
2003-02-06 07:32:57 +00:00
|
|
|
|
2003-09-03 04:30:29 +00:00
|
|
|
GetDirListing( sDir+sFileName+"*.redir", matches, false, true );
|
2003-09-16 00:48:30 +00:00
|
|
|
GetDirListing( sDir+sFileName+"*.model", matches, false, true );
|
2003-09-03 04:30:29 +00:00
|
|
|
GetDirListing( sDir+sFileName+"*.txt", matches, false, true );
|
|
|
|
|
GetDirListing( sDir+sFileName+"*.sprite", matches, false, true );
|
|
|
|
|
GetDirListing( sDir+sFileName+"*.png", matches, false, true );
|
|
|
|
|
GetDirListing( sDir+sFileName+"*.jpg", matches, false, true );
|
|
|
|
|
GetDirListing( sDir+sFileName+"*.bmp", matches, false, true );
|
|
|
|
|
GetDirListing( sDir+sFileName+"*.gif", matches, false, true );
|
2003-02-06 07:32:57 +00:00
|
|
|
|
2003-09-03 04:30:29 +00:00
|
|
|
if( matches.empty() )
|
2003-02-06 07:32:57 +00:00
|
|
|
return "";
|
2003-09-03 04:30:29 +00:00
|
|
|
|
|
|
|
|
if( matches.size() > 1 )
|
|
|
|
|
{
|
|
|
|
|
CString sError = "Multiple files match '"+sDir+sFileName+"'. Please remove all but one of these files.";
|
|
|
|
|
if( DISPLAY->IsWindowed() )
|
|
|
|
|
HOOKS->MessageBoxOK( sError );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CString sPath = matches[0];
|
|
|
|
|
|
|
|
|
|
bool bIsARedirect = GetExtension(sPath).CompareNoCase("redir")==0;
|
|
|
|
|
if( !bIsARedirect )
|
|
|
|
|
{
|
|
|
|
|
return sPath;
|
|
|
|
|
}
|
|
|
|
|
else // bIsARedirect
|
|
|
|
|
{
|
|
|
|
|
CString sNewFileName = GetRedirContents(sPath);
|
|
|
|
|
|
|
|
|
|
CString sNewPath = GetPathTo(sDir, sNewFileName);
|
|
|
|
|
|
|
|
|
|
if( !sNewPath.empty() )
|
|
|
|
|
return sNewPath;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CString message = ssprintf(
|
|
|
|
|
"ThemeManager: The redirect '%s' points to the file '%s', which does not exist. "
|
|
|
|
|
"Verify that this redirect is correct.",
|
|
|
|
|
sPath.c_str(), sNewFileName.c_str());
|
|
|
|
|
|
|
|
|
|
RageException::Throw( "%s", message.c_str() );
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-02-06 07:32:57 +00:00
|
|
|
}
|