no message
This commit is contained in:
+28
-9
@@ -77,7 +77,9 @@ void Actor::Draw() // set the world matrix and calculate actor properties, the
|
||||
m_temp_colorDiffuse[i] = m_effect_colorDiffuse1*m_fPercentBetweenColors + m_effect_colorDiffuse2*(1.0f-m_fPercentBetweenColors);
|
||||
break;
|
||||
case glowing:
|
||||
m_temp_colorAdd = m_effect_colorAdd1*m_fPercentBetweenColors + m_effect_colorAdd2*(1.0f-m_fPercentBetweenColors);
|
||||
float fCurvedPercent;
|
||||
fCurvedPercent = sinf( m_fPercentBetweenColors * D3DX_PI );
|
||||
m_temp_colorAdd = m_effect_colorAdd1*fCurvedPercent + m_effect_colorAdd2*(1.0f-fCurvedPercent);
|
||||
break;
|
||||
case wagging:
|
||||
m_temp_rotation.z = m_fWagRadians * sinf(
|
||||
@@ -223,25 +225,42 @@ void Actor::Update( float fDeltaTime )
|
||||
}
|
||||
else // in the middle of tweening. Recalcute the curent position.
|
||||
{
|
||||
float fPercentThroughTween = 1-(TS.m_fTimeLeftInTween / TS.m_fTweenTime);
|
||||
const float fPercentThroughTween = 1-(TS.m_fTimeLeftInTween / TS.m_fTweenTime);
|
||||
|
||||
float fPercentAlongPath;
|
||||
|
||||
// distort the percentage if appropriate
|
||||
switch( TS.m_TweenType )
|
||||
{
|
||||
case TWEEN_LINEAR:
|
||||
fPercentAlongPath = fPercentThroughTween;
|
||||
break;
|
||||
case TWEEN_BIAS_BEGIN:
|
||||
fPercentThroughTween = (float) sqrt( fPercentThroughTween );
|
||||
fPercentAlongPath = (float) sqrt( fPercentThroughTween );
|
||||
break;
|
||||
case TWEEN_BIAS_END:
|
||||
fPercentThroughTween = fPercentThroughTween * fPercentThroughTween;
|
||||
fPercentAlongPath = fPercentThroughTween * fPercentThroughTween;
|
||||
break;
|
||||
case TWEEN_BOUNCE_BEGIN:
|
||||
fPercentAlongPath = 1 - sinf( 1.1f + fPercentThroughTween*(D3DX_PI-1.1f) ) / 0.89f;
|
||||
break;
|
||||
case TWEEN_BOUNCE_END:
|
||||
fPercentAlongPath = sinf( 1.1f + (1-fPercentThroughTween)*(D3DX_PI-1.1f) ) / 0.89f;
|
||||
break;
|
||||
case TWEEN_SPRING:
|
||||
fPercentAlongPath = 1 - cosf( fPercentThroughTween*D3DX_PI*2.5f )/(1+fPercentThroughTween*3);
|
||||
break;
|
||||
default:
|
||||
ASSERT( false );
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
m_pos = m_start_pos + (TS.m_end_pos - m_start_pos )*fPercentThroughTween;
|
||||
m_scale = m_start_scale + (TS.m_end_scale - m_start_scale )*fPercentThroughTween;
|
||||
m_rotation = m_start_rotation+ (TS.m_end_rotation - m_start_rotation)*fPercentThroughTween;
|
||||
for(int i=0; i<4; i++) m_colorDiffuse[i] = m_start_colorDiffuse[i]*(1.0f-fPercentThroughTween) + TS.m_end_colorDiffuse[i]*(fPercentThroughTween);
|
||||
m_colorAdd = m_start_colorAdd *(1.0f-fPercentThroughTween) + TS.m_end_colorAdd *(fPercentThroughTween);
|
||||
m_pos = m_start_pos + (TS.m_end_pos - m_start_pos )*fPercentAlongPath;
|
||||
m_scale = m_start_scale + (TS.m_end_scale - m_start_scale )*fPercentAlongPath;
|
||||
m_rotation = m_start_rotation+ (TS.m_end_rotation - m_start_rotation)*fPercentAlongPath;
|
||||
for(int i=0; i<4; i++) m_colorDiffuse[i] = m_start_colorDiffuse[i]*(1.0f-fPercentAlongPath) + TS.m_end_colorDiffuse[i]*(fPercentAlongPath);
|
||||
m_colorAdd = m_start_colorAdd *(1.0f-fPercentAlongPath) + TS.m_end_colorAdd *(fPercentAlongPath);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -29,7 +29,14 @@ public:
|
||||
|
||||
|
||||
|
||||
enum TweenType { TWEEN_LINEAR, TWEEN_BIAS_BEGIN, TWEEN_BIAS_END };
|
||||
enum TweenType {
|
||||
TWEEN_LINEAR,
|
||||
TWEEN_BIAS_BEGIN,
|
||||
TWEEN_BIAS_END,
|
||||
TWEEN_BOUNCE_BEGIN,
|
||||
TWEEN_BOUNCE_END,
|
||||
TWEEN_SPRING,
|
||||
};
|
||||
enum Effect { no_effect,
|
||||
blinking, camelion, glowing,
|
||||
wagging, spinning,
|
||||
|
||||
@@ -47,7 +47,7 @@ float ArrowGetXPos( const PlayerOptions& po, const StyleDef &StyleDef, int iColN
|
||||
|
||||
float ArrowGetRotation( const PlayerOptions& po, const StyleDef &StyleDef, int iColNum, float fYOffset )
|
||||
{
|
||||
float fRotation = StyleDef.m_ColumnToRotation[iColNum];
|
||||
float fRotation = 0; //StyleDef.m_ColumnToRotation[iColNum];
|
||||
|
||||
switch( po.m_EffectType )
|
||||
{
|
||||
|
||||
@@ -56,9 +56,10 @@ bool GameManager::IsPlayerEnabled( PlayerNumber PlayerNo )
|
||||
|
||||
StyleDef GameManager::GetStyleDef( DanceStyle mode )
|
||||
{
|
||||
StyleDef StyleDef;
|
||||
StyleDef sd;
|
||||
|
||||
|
||||
/*
|
||||
CMap<TapNote, TapNote, float, float> mapTapNoteToRotation; // arrow facing left is rotation 0
|
||||
mapTapNoteToRotation[NOTE_PAD1_LEFT] = 0;
|
||||
mapTapNoteToRotation[NOTE_PAD1_UPLEFT] = D3DX_PI/4.0f;
|
||||
@@ -72,18 +73,18 @@ StyleDef GameManager::GetStyleDef( DanceStyle mode )
|
||||
mapTapNoteToRotation[NOTE_PAD2_UP] = mapTapNoteToRotation[NOTE_PAD1_UP];
|
||||
mapTapNoteToRotation[NOTE_PAD2_UPRIGHT] = mapTapNoteToRotation[NOTE_PAD1_UPRIGHT];
|
||||
mapTapNoteToRotation[NOTE_PAD2_RIGHT] = mapTapNoteToRotation[NOTE_PAD1_RIGHT];
|
||||
|
||||
*/
|
||||
|
||||
switch( mode )
|
||||
{
|
||||
case STYLE_SINGLE:
|
||||
case STYLE_DOUBLE:
|
||||
case STYLE_SOLO:
|
||||
StyleDef.m_iNumPlayers = 1;
|
||||
sd.m_iNumPlayers = 1;
|
||||
break;
|
||||
case STYLE_VERSUS:
|
||||
case STYLE_COUPLE:
|
||||
StyleDef.m_iNumPlayers = 2;
|
||||
sd.m_iNumPlayers = 2;
|
||||
break;
|
||||
default:
|
||||
ASSERT( false ); // invalid GameMode
|
||||
@@ -95,65 +96,85 @@ StyleDef GameManager::GetStyleDef( DanceStyle mode )
|
||||
case STYLE_SINGLE:
|
||||
case STYLE_VERSUS:
|
||||
case STYLE_COUPLE:
|
||||
StyleDef.m_iNumColumns = 4; // LEFT, DOWN, UP, RIGHT
|
||||
StyleDef.m_ColumnToTapNote[0] = NOTE_PAD1_LEFT;
|
||||
StyleDef.m_ColumnToTapNote[1] = NOTE_PAD1_DOWN;
|
||||
StyleDef.m_ColumnToTapNote[2] = NOTE_PAD1_UP;
|
||||
StyleDef.m_ColumnToTapNote[3] = NOTE_PAD1_RIGHT;
|
||||
StyleDef.m_ColumnToTapNote[4] = NOTE_PAD1_UPLEFT; // Even though this isn't used, Need them here so
|
||||
StyleDef.m_ColumnToTapNote[5] = NOTE_PAD1_UPRIGHT; // TapNoteToColumnNumber doesn't get confused by them
|
||||
StyleDef.m_ColumnToRotation[0] = mapTapNoteToRotation[NOTE_PAD1_LEFT];
|
||||
StyleDef.m_ColumnToRotation[1] = mapTapNoteToRotation[NOTE_PAD1_DOWN];
|
||||
StyleDef.m_ColumnToRotation[2] = mapTapNoteToRotation[NOTE_PAD1_UP];
|
||||
StyleDef.m_ColumnToRotation[3] = mapTapNoteToRotation[NOTE_PAD1_RIGHT];
|
||||
StyleDef.m_ColumnToRotation[4] = mapTapNoteToRotation[NOTE_PAD1_UPLEFT];
|
||||
StyleDef.m_ColumnToRotation[5] = mapTapNoteToRotation[NOTE_PAD1_UPRIGHT];
|
||||
break;
|
||||
sd.m_iNumColumns = 4;
|
||||
sd.m_ColumnToTapNote[0] = NOTE_PAD1_LEFT;
|
||||
sd.m_ColumnToTapNote[1] = NOTE_PAD1_DOWN;
|
||||
sd.m_ColumnToTapNote[2] = NOTE_PAD1_UP;
|
||||
sd.m_ColumnToTapNote[3] = NOTE_PAD1_RIGHT;
|
||||
sd.m_sColumnToNoteName[0] = "left";
|
||||
sd.m_sColumnToNoteName[1] = "down";
|
||||
sd.m_sColumnToNoteName[2] = "up";
|
||||
sd.m_sColumnToNoteName[3] = "right";
|
||||
/* sd.m_ColumnToRotation[0] = mapTapNoteToRotation[NOTE_PAD1_LEFT];
|
||||
sd.m_ColumnToRotation[1] = mapTapNoteToRotation[NOTE_PAD1_DOWN];
|
||||
sd.m_ColumnToRotation[2] = mapTapNoteToRotation[NOTE_PAD1_UP];
|
||||
sd.m_ColumnToRotation[3] = mapTapNoteToRotation[NOTE_PAD1_RIGHT];
|
||||
*/ break;
|
||||
case STYLE_SOLO:
|
||||
StyleDef.m_iNumColumns = 6; // LEFT, UP+LEFT, DOWN, UP, UP+RIGHT, RIGHT
|
||||
StyleDef.m_ColumnToTapNote[0] = NOTE_PAD1_LEFT;
|
||||
StyleDef.m_ColumnToTapNote[1] = NOTE_PAD1_UPLEFT;
|
||||
StyleDef.m_ColumnToTapNote[2] = NOTE_PAD1_DOWN;
|
||||
StyleDef.m_ColumnToTapNote[3] = NOTE_PAD1_UP;
|
||||
StyleDef.m_ColumnToTapNote[4] = NOTE_PAD1_UPRIGHT;
|
||||
StyleDef.m_ColumnToTapNote[5] = NOTE_PAD1_RIGHT;
|
||||
StyleDef.m_ColumnToRotation[0] = mapTapNoteToRotation[NOTE_PAD1_LEFT];
|
||||
StyleDef.m_ColumnToRotation[1] = mapTapNoteToRotation[NOTE_PAD1_UPLEFT];
|
||||
StyleDef.m_ColumnToRotation[2] = mapTapNoteToRotation[NOTE_PAD1_DOWN];
|
||||
StyleDef.m_ColumnToRotation[3] = mapTapNoteToRotation[NOTE_PAD1_UP];
|
||||
StyleDef.m_ColumnToRotation[4] = mapTapNoteToRotation[NOTE_PAD1_UPRIGHT];
|
||||
StyleDef.m_ColumnToRotation[5] = mapTapNoteToRotation[NOTE_PAD1_RIGHT];
|
||||
break;
|
||||
sd.m_iNumColumns = 6; // LEFT, UP+LEFT, DOWN, UP, UP+RIGHT, RIGHT
|
||||
sd.m_ColumnToTapNote[0] = NOTE_PAD1_LEFT;
|
||||
sd.m_ColumnToTapNote[1] = NOTE_PAD1_UPLEFT;
|
||||
sd.m_ColumnToTapNote[2] = NOTE_PAD1_DOWN;
|
||||
sd.m_ColumnToTapNote[3] = NOTE_PAD1_UP;
|
||||
sd.m_ColumnToTapNote[4] = NOTE_PAD1_UPRIGHT;
|
||||
sd.m_ColumnToTapNote[5] = NOTE_PAD1_RIGHT;
|
||||
sd.m_sColumnToNoteName[0] = "left";
|
||||
sd.m_sColumnToNoteName[1] = "upleft";
|
||||
sd.m_sColumnToNoteName[2] = "down";
|
||||
sd.m_sColumnToNoteName[3] = "up";
|
||||
sd.m_sColumnToNoteName[4] = "upright";
|
||||
sd.m_sColumnToNoteName[5] = "right";
|
||||
/* sd.m_ColumnToRotation[0] = mapTapNoteToRotation[NOTE_PAD1_LEFT];
|
||||
sd.m_ColumnToRotation[1] = mapTapNoteToRotation[NOTE_PAD1_UPLEFT];
|
||||
sd.m_ColumnToRotation[2] = mapTapNoteToRotation[NOTE_PAD1_DOWN];
|
||||
sd.m_ColumnToRotation[3] = mapTapNoteToRotation[NOTE_PAD1_UP];
|
||||
sd.m_ColumnToRotation[4] = mapTapNoteToRotation[NOTE_PAD1_UPRIGHT];
|
||||
sd.m_ColumnToRotation[5] = mapTapNoteToRotation[NOTE_PAD1_RIGHT];
|
||||
*/ break;
|
||||
case STYLE_DOUBLE:
|
||||
StyleDef.m_iNumColumns = 8; // 1_LEFT, 1_DOWN, 1_UP, 1_RIGHT, 2_LEFT, 2_DOWN, 2_UP, 2_RIGHT
|
||||
StyleDef.m_ColumnToTapNote[0] = NOTE_PAD1_LEFT;
|
||||
StyleDef.m_ColumnToTapNote[1] = NOTE_PAD1_DOWN;
|
||||
StyleDef.m_ColumnToTapNote[2] = NOTE_PAD1_UP;
|
||||
StyleDef.m_ColumnToTapNote[3] = NOTE_PAD1_RIGHT;
|
||||
StyleDef.m_ColumnToTapNote[4] = NOTE_PAD2_LEFT;
|
||||
StyleDef.m_ColumnToTapNote[5] = NOTE_PAD2_DOWN;
|
||||
StyleDef.m_ColumnToTapNote[6] = NOTE_PAD2_UP;
|
||||
StyleDef.m_ColumnToTapNote[7] = NOTE_PAD2_RIGHT;
|
||||
StyleDef.m_ColumnToTapNote[8] = NOTE_PAD1_UPLEFT;// Even though this isn't used, Need them here so
|
||||
StyleDef.m_ColumnToTapNote[9] = NOTE_PAD1_UPRIGHT;// TapNoteToColumnNumber doesn't get confused by them
|
||||
StyleDef.m_ColumnToTapNote[10] = NOTE_PAD2_UPLEFT;
|
||||
StyleDef.m_ColumnToTapNote[11] = NOTE_PAD2_UPRIGHT;
|
||||
StyleDef.m_ColumnToRotation[0] = mapTapNoteToRotation[NOTE_PAD1_LEFT];
|
||||
StyleDef.m_ColumnToRotation[1] = mapTapNoteToRotation[NOTE_PAD1_DOWN];
|
||||
StyleDef.m_ColumnToRotation[2] = mapTapNoteToRotation[NOTE_PAD1_UP];
|
||||
StyleDef.m_ColumnToRotation[3] = mapTapNoteToRotation[NOTE_PAD1_RIGHT];
|
||||
StyleDef.m_ColumnToRotation[4] = mapTapNoteToRotation[NOTE_PAD2_LEFT];
|
||||
StyleDef.m_ColumnToRotation[5] = mapTapNoteToRotation[NOTE_PAD2_DOWN];
|
||||
StyleDef.m_ColumnToRotation[6] = mapTapNoteToRotation[NOTE_PAD2_UP];
|
||||
StyleDef.m_ColumnToRotation[7] = mapTapNoteToRotation[NOTE_PAD2_RIGHT];
|
||||
StyleDef.m_ColumnToRotation[8] = mapTapNoteToRotation[NOTE_PAD1_UPLEFT];
|
||||
StyleDef.m_ColumnToRotation[9] = mapTapNoteToRotation[NOTE_PAD1_UPRIGHT];
|
||||
StyleDef.m_ColumnToRotation[10] = mapTapNoteToRotation[NOTE_PAD2_UPLEFT];
|
||||
StyleDef.m_ColumnToRotation[11] = mapTapNoteToRotation[NOTE_PAD2_UPRIGHT];
|
||||
sd.m_iNumColumns = 8; // 1_LEFT, 1_DOWN, 1_UP, 1_RIGHT, 2_LEFT, 2_DOWN, 2_UP, 2_RIGHT
|
||||
sd.m_ColumnToTapNote[0] = NOTE_PAD1_LEFT;
|
||||
sd.m_ColumnToTapNote[1] = NOTE_PAD1_DOWN;
|
||||
sd.m_ColumnToTapNote[2] = NOTE_PAD1_UP;
|
||||
sd.m_ColumnToTapNote[3] = NOTE_PAD1_RIGHT;
|
||||
sd.m_ColumnToTapNote[4] = NOTE_PAD2_LEFT;
|
||||
sd.m_ColumnToTapNote[5] = NOTE_PAD2_DOWN;
|
||||
sd.m_ColumnToTapNote[6] = NOTE_PAD2_UP;
|
||||
sd.m_ColumnToTapNote[7] = NOTE_PAD2_RIGHT;
|
||||
sd.m_ColumnToTapNote[8] = NOTE_PAD1_UPLEFT;// Even though this isn't used, Need them here so
|
||||
sd.m_ColumnToTapNote[9] = NOTE_PAD1_UPRIGHT;// TapNoteToColumnNumber doesn't get confused by them
|
||||
sd.m_ColumnToTapNote[10] = NOTE_PAD2_UPLEFT;
|
||||
sd.m_ColumnToTapNote[11] = NOTE_PAD2_UPRIGHT;
|
||||
sd.m_sColumnToNoteName[0] = "left";
|
||||
sd.m_sColumnToNoteName[1] = "upleft";
|
||||
sd.m_sColumnToNoteName[2] = "down";
|
||||
sd.m_sColumnToNoteName[3] = "up";
|
||||
sd.m_sColumnToNoteName[4] = "upright";
|
||||
sd.m_sColumnToNoteName[5] = "right";
|
||||
sd.m_sColumnToNoteName[6] = "left";
|
||||
sd.m_sColumnToNoteName[7] = "upleft";
|
||||
sd.m_sColumnToNoteName[8] = "down";
|
||||
sd.m_sColumnToNoteName[9] = "up";
|
||||
sd.m_sColumnToNoteName[10] = "upright";
|
||||
sd.m_sColumnToNoteName[11] = "right";
|
||||
/*
|
||||
sd.m_ColumnToRotation[0] = mapTapNoteToRotation[NOTE_PAD1_LEFT];
|
||||
sd.m_ColumnToRotation[1] = mapTapNoteToRotation[NOTE_PAD1_DOWN];
|
||||
sd.m_ColumnToRotation[2] = mapTapNoteToRotation[NOTE_PAD1_UP];
|
||||
sd.m_ColumnToRotation[3] = mapTapNoteToRotation[NOTE_PAD1_RIGHT];
|
||||
sd.m_ColumnToRotation[4] = mapTapNoteToRotation[NOTE_PAD2_LEFT];
|
||||
sd.m_ColumnToRotation[5] = mapTapNoteToRotation[NOTE_PAD2_DOWN];
|
||||
sd.m_ColumnToRotation[6] = mapTapNoteToRotation[NOTE_PAD2_UP];
|
||||
sd.m_ColumnToRotation[7] = mapTapNoteToRotation[NOTE_PAD2_RIGHT];
|
||||
sd.m_ColumnToRotation[8] = mapTapNoteToRotation[NOTE_PAD1_UPLEFT];
|
||||
sd.m_ColumnToRotation[9] = mapTapNoteToRotation[NOTE_PAD1_UPRIGHT];
|
||||
sd.m_ColumnToRotation[10] = mapTapNoteToRotation[NOTE_PAD2_UPLEFT];
|
||||
sd.m_ColumnToRotation[11] = mapTapNoteToRotation[NOTE_PAD2_UPRIGHT];
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
ASSERT( false ); // invalid GameMode
|
||||
}
|
||||
|
||||
return StyleDef;
|
||||
return sd;
|
||||
}
|
||||
@@ -16,7 +16,7 @@ const float GRAY_ARROW_TWEEN_TIME = 0.5f;
|
||||
|
||||
GhostArrow::GhostArrow()
|
||||
{
|
||||
Load( THEME->GetPathTo(GRAPHIC_GHOST_ARROW) );
|
||||
// Load( THEME->GetPathTo(GRAPHIC_GHOST_ARROW) );
|
||||
SetDiffuseColor( D3DXCOLOR(1,1,1,0) );
|
||||
TurnShadowOff();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ const float GRAY_ARROW_TWEEN_TIME = 0.5f;
|
||||
|
||||
GhostArrowBright::GhostArrowBright()
|
||||
{
|
||||
Load( THEME->GetPathTo(GRAPHIC_BRIGHT_GHOST_ARROW) );
|
||||
// Load( THEME->GetPathTo(GRAPHIC_BRIGHT_GHOST_ARROW) );
|
||||
SetDiffuseColor( D3DXCOLOR(1,1,1,0) );
|
||||
TurnShadowOff();
|
||||
}
|
||||
|
||||
@@ -19,13 +19,12 @@ const float GRAY_ARROW_POP_UP_TIME = 0.3f;
|
||||
|
||||
GrayArrow::GrayArrow()
|
||||
{
|
||||
Load( THEME->GetPathTo(GRAPHIC_GRAY_ARROW) );
|
||||
StopAnimating();
|
||||
}
|
||||
|
||||
void GrayArrow::SetBeat( const float fSongBeat )
|
||||
{
|
||||
SetState( fmod(fSongBeat,1)<0.25 ? 1 : 0 );
|
||||
SetState( fmod(fSongBeat,1) * Sprite::GetNumStates() );
|
||||
}
|
||||
|
||||
void GrayArrow::Step()
|
||||
|
||||
@@ -20,7 +20,7 @@ HoldGhostArrow::HoldGhostArrow()
|
||||
m_bWasSteppedOnLastFrame = false;
|
||||
m_fHeatLevel = 0;
|
||||
|
||||
LoadFromSpriteFile( THEME->GetPathTo(GRAPHIC_HOLD_GHOST_ARROW) );
|
||||
// LoadFromSpriteFile( THEME->GetPathTo(GRAPHIC_HOLD_GHOST_ARROW) );
|
||||
SetDiffuseColor( D3DXCOLOR(1,1,1,1) );
|
||||
SetZoom( 1.1f );
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ void Player::Load( const StyleDef& StyleDef, PlayerNumber player_no, const Patte
|
||||
if( po.m_bLittle )
|
||||
pattern2.MakeLittle();
|
||||
|
||||
m_ColorArrowField.Load( StyleDef, pattern2, po, 1.5f, 5.5f );
|
||||
m_ColorArrowField.Load( StyleDef, pattern2, po, 1.5f, 5.5f, ColorArrowField::MODE_DANCING );
|
||||
m_GrayArrows.Load( po, StyleDef );
|
||||
m_GhostArrows.Load( po, StyleDef );
|
||||
|
||||
|
||||
@@ -288,3 +288,30 @@ CString SongManager::GetGroupBannerPath( CString sGroupName )
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
void SongManager::GetGroupNames( CStringArray &AddTo )
|
||||
{
|
||||
CArray<Song*, Song*> arraySongs;
|
||||
arraySongs.Copy( m_pSongs );
|
||||
SortSongPointerArrayByGroup( arraySongs );
|
||||
|
||||
for( int i=0; i<m_pSongs.GetSize(); i++ )
|
||||
{
|
||||
Song* pSong = m_pSongs[i];
|
||||
const CString sGroupName = m_pSongs[i]->GetGroupName();
|
||||
|
||||
if( AddTo.GetSize() == 0 || AddTo[AddTo.GetSize()-1] != sGroupName )
|
||||
AddTo.Add( sGroupName );
|
||||
}
|
||||
}
|
||||
|
||||
void SongManager::GetSongsInGroup( const CString sGroupName, CArray<Song*, Song*> &AddTo )
|
||||
{
|
||||
for( int i=0; i<m_pSongs.GetSize(); i++ )
|
||||
{
|
||||
Song* pSong = m_pSongs[i];
|
||||
if( sGroupName == m_pSongs[i]->GetGroupName() )
|
||||
AddTo.Add( pSong );
|
||||
}
|
||||
SortSongPointerArrayByGroup( AddTo );
|
||||
}
|
||||
|
||||
@@ -40,6 +40,11 @@ public:
|
||||
|
||||
|
||||
CString GetGroupBannerPath( CString sGroupName );
|
||||
|
||||
void GetGroupNames( CStringArray &AddTo );
|
||||
|
||||
void GetSongsInGroup( const CString sGroupName, CArray<Song*,Song*> &AddTo );
|
||||
|
||||
|
||||
protected:
|
||||
void LoadStepManiaSongDir( CString sDir );
|
||||
|
||||
@@ -10,5 +10,46 @@
|
||||
*/
|
||||
|
||||
#include "StyleDef.h"
|
||||
#include "RageHelper.h"
|
||||
#include "RageUtil.h"
|
||||
|
||||
|
||||
CString StyleDef::ElementToGraphicSuffix( const StyleElement se )
|
||||
{
|
||||
CString sAssetPath; // fill this in below
|
||||
|
||||
switch( se )
|
||||
{
|
||||
case GRAPHIC_NOTE_COLOR_PART: sAssetPath = "note color part"; break;
|
||||
case GRAPHIC_NOTE_GRAY_PART: sAssetPath = "note gray part"; break;
|
||||
case GRAPHIC_RECEPTOR: sAssetPath = "receptor"; break;
|
||||
case GRAPHIC_HOLD_EXPLOSION: sAssetPath = "hold explosion"; break;
|
||||
case GRAPHIC_TAP_EXPLOSION_BRIGHT: sAssetPath = "tap explosion bright"; break;
|
||||
case GRAPHIC_TAP_EXPLOSION_DIM: sAssetPath = "tap explosion dim"; break;
|
||||
|
||||
default:
|
||||
HELPER.FatalError( ssprintf("Unhandled StyleElement %d", se) );
|
||||
}
|
||||
|
||||
return sAssetPath;
|
||||
}
|
||||
|
||||
CString StyleDef::GetPathToGraphic( const int iColumnNumber, const StyleElement se )
|
||||
{
|
||||
const CString sDir = "Game\\Dance\\";
|
||||
const CString sNoteName = m_sColumnToNoteName[ iColumnNumber ];
|
||||
const CString sGraphicSuffix = ElementToGraphicSuffix( se );
|
||||
|
||||
CStringArray arrayPossibleElementFileNames; // fill this with the possible files
|
||||
|
||||
GetDirListing( ssprintf("%s%s %s*.sprite", sDir, sNoteName, sGraphicSuffix), arrayPossibleElementFileNames );
|
||||
GetDirListing( ssprintf("%s%s %s*.png", sDir, sNoteName, sGraphicSuffix), arrayPossibleElementFileNames );
|
||||
GetDirListing( ssprintf("%s%s %s*.jpg", sDir, sNoteName, sGraphicSuffix), arrayPossibleElementFileNames );
|
||||
GetDirListing( ssprintf("%s%s %s*.bmp", sDir, sNoteName, sGraphicSuffix), arrayPossibleElementFileNames );
|
||||
|
||||
if( arrayPossibleElementFileNames.GetSize() > 0 )
|
||||
return sDir + arrayPossibleElementFileNames[0];
|
||||
|
||||
HELPER.FatalError( "The style graphic '%s' if missing from '%s'.", sNoteName+" "+sGraphicSuffix, sDir );
|
||||
return "";
|
||||
}
|
||||
@@ -16,14 +16,26 @@
|
||||
|
||||
const int MAX_NUM_COLUMNS = 12;
|
||||
|
||||
enum StyleElement {
|
||||
GRAPHIC_NOTE_COLOR_PART,
|
||||
GRAPHIC_NOTE_GRAY_PART,
|
||||
GRAPHIC_RECEPTOR,
|
||||
GRAPHIC_TAP_EXPLOSION_BRIGHT,
|
||||
GRAPHIC_TAP_EXPLOSION_DIM,
|
||||
GRAPHIC_HOLD_EXPLOSION,
|
||||
|
||||
NUM_STYLE_ELEMENTS // leave this at the end
|
||||
};
|
||||
|
||||
struct StyleDef
|
||||
{
|
||||
public:
|
||||
int m_iNumPlayers;
|
||||
int m_iNumColumns; // will vary depending on the number panels (4,6,8,etc)
|
||||
TapNote m_ColumnToTapNote[MAX_NUM_COLUMNS];
|
||||
float m_ColumnToRotation[MAX_NUM_COLUMNS];
|
||||
|
||||
CString m_sColumnToNoteName[MAX_NUM_COLUMNS]; // e.g. "left", "right", "middle C", "snare"
|
||||
TapNote m_ColumnToTapNote[MAX_NUM_COLUMNS]; // which TapNote does this column correspond to?
|
||||
CString GetPathToGraphic( const int iColumnNumber, const StyleElement se );
|
||||
|
||||
inline int TapNoteToColumnNumber( TapNote tap_step )
|
||||
{
|
||||
@@ -36,6 +48,9 @@ struct StyleDef
|
||||
return -1; // the TapNote is not used in this StyleDef
|
||||
};
|
||||
|
||||
protected:
|
||||
CString ElementToGraphicSuffix( const StyleElement se );
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ bool TextBanner::LoadFromSong( Song* pSong )
|
||||
|
||||
m_textTitle.SetText( sTitle );
|
||||
m_textSubTitle.SetText( sSubTitle );
|
||||
m_textArtist.SetText( "/" + pSong->GetArtist() );
|
||||
m_textArtist.SetText( "/ " + pSong->GetArtist() );
|
||||
|
||||
|
||||
float fTitleZoom, fSubTitleZoom, fArtistZoom;
|
||||
|
||||
@@ -99,12 +99,6 @@ CString ThemeManager::ElementToAssetPath( ThemeElement te )
|
||||
case GRAPHIC_RESULT_TOP_EDGE: sAssetPath = "Graphics\\result top edge"; break;
|
||||
case GRAPHIC_FALLBACK_BANNER: sAssetPath = "Graphics\\Fallback Banner"; break;
|
||||
case GRAPHIC_FALLBACK_BACKGROUND: sAssetPath = "Graphics\\Fallback Background"; break;
|
||||
case GRAPHIC_COLOR_ARROW_GRAY_PART: sAssetPath = "Graphics\\Color Arrow gray part 2x2"; break;
|
||||
case GRAPHIC_COLOR_ARROW_COLOR_PART: sAssetPath = "Graphics\\Color Arrow color part"; break;
|
||||
case GRAPHIC_GHOST_ARROW: sAssetPath = "Graphics\\ghost arrow"; break;
|
||||
case GRAPHIC_BRIGHT_GHOST_ARROW: sAssetPath = "Graphics\\bright ghost arrow"; break;
|
||||
case GRAPHIC_HOLD_GHOST_ARROW: sAssetPath = "Graphics\\hold ghost arrow"; break;
|
||||
case GRAPHIC_GRAY_ARROW: sAssetPath = "Graphics\\gray arrow"; break;
|
||||
case GRAPHIC_JUDGEMENT: sAssetPath = "Graphics\\judgement 1x9"; break;
|
||||
case GRAPHIC_MENU_BOTTOM_EDGE: sAssetPath = "Graphics\\menu bottom edge"; break;
|
||||
case GRAPHIC_SCORE_FRAME: sAssetPath = "Graphics\\score frame"; break;
|
||||
@@ -144,13 +138,15 @@ CString ThemeManager::ElementToAssetPath( ThemeElement te )
|
||||
case GRAPHIC_SYNCHRONIZE_BACKGROUND: sAssetPath = "Graphics\\synchronize background"; break;
|
||||
case GRAPHIC_SYNCHRONIZE_TOP_EDGE: sAssetPath = "Graphics\\synchronize top edge"; break;
|
||||
case GRAPHIC_TITLE_MENU_LOGO: sAssetPath = "Graphics\\title menu logo"; break;
|
||||
case GRAPHIC_TITLE_MENU_HELP: sAssetPath = "Graphics\\title menu help"; break;
|
||||
case GRAPHIC_SELECT_DIFFICULTY_BACKGROUND: sAssetPath = "Graphics\\select difficulty background"; break;
|
||||
case GRAPHIC_SELECT_DIFFICULTY_TOP_EDGE: sAssetPath = "Graphics\\select difficulty top edge"; break;
|
||||
case GRAPHIC_SELECT_DIFFICULTY_EXPLANATION: sAssetPath = "Graphics\\select difficulty explanation"; break;
|
||||
case GRAPHIC_SELECT_DIFFICULTY_EASY: sAssetPath = "Graphics\\select difficulty easy"; break;
|
||||
case GRAPHIC_SELECT_DIFFICULTY_MEDIUM: sAssetPath = "Graphics\\select difficulty medium"; break;
|
||||
case GRAPHIC_SELECT_DIFFICULTY_HARD: sAssetPath = "Graphics\\select difficulty hard"; break;
|
||||
case GRAPHIC_SELECT_DIFFICULTY_BACKGROUND: sAssetPath = "Graphics\\select difficulty background"; break;
|
||||
case GRAPHIC_SELECT_DIFFICULTY_TOP_EDGE: sAssetPath = "Graphics\\select difficulty top edge"; break;
|
||||
case GRAPHIC_SELECT_DIFFICULTY_EXPLANATION: sAssetPath = "Graphics\\select difficulty explanation"; break;
|
||||
case GRAPHIC_SELECT_DIFFICULTY_EASY_HEADER: sAssetPath = "Graphics\\select difficulty easy header"; break;
|
||||
case GRAPHIC_SELECT_DIFFICULTY_MEDIUM_HEADER: sAssetPath = "Graphics\\select difficulty medium header"; break;
|
||||
case GRAPHIC_SELECT_DIFFICULTY_HARD_HEADER: sAssetPath = "Graphics\\select difficulty hard header"; break;
|
||||
case GRAPHIC_SELECT_DIFFICULTY_EASY_PICTURE: sAssetPath = "Graphics\\select difficulty easy picture"; break;
|
||||
case GRAPHIC_SELECT_DIFFICULTY_MEDIUM_PICTURE: sAssetPath = "Graphics\\select difficulty medium picture"; break;
|
||||
case GRAPHIC_SELECT_DIFFICULTY_HARD_PICTURE: sAssetPath = "Graphics\\select difficulty hard picture"; break;
|
||||
case GRAPHIC_SELECT_DIFFICULTY_ARROW: sAssetPath = "Graphics\\select difficulty arrow"; break;
|
||||
case GRAPHIC_SELECT_DIFFICULTY_OK: sAssetPath = "Graphics\\select difficulty ok"; break;
|
||||
case GRAPHIC_SELECT_MUSIC_INFO_FRAME: sAssetPath = "Graphics\\select music info frame"; break;
|
||||
@@ -172,6 +168,7 @@ CString ThemeManager::ElementToAssetPath( ThemeElement te )
|
||||
case SOUND_INVALID: sAssetPath = "Sounds\\invalid"; break;
|
||||
case SOUND_EDIT_CHANGE_LINE: sAssetPath = "Sounds\\edit change line"; break;
|
||||
case SOUND_EDIT_CHANGE_SNAP: sAssetPath = "Sounds\\edit change snap"; break;
|
||||
case SOUND_SELECT_DIFFICULTY_CHANGE: sAssetPath = "Sounds\\select difficulty change"; break;
|
||||
|
||||
case FONT_BOLD: sAssetPath = "Fonts\\Bold"; break;
|
||||
case FONT_COMBO_NUMBERS: sAssetPath = "Fonts\\Combo Numbers"; break;
|
||||
|
||||
@@ -19,75 +19,71 @@
|
||||
|
||||
enum ThemeElement {
|
||||
GRAPHIC_TITLE_MENU_BACKGROUND,
|
||||
GRAPHIC_SELECT_STYLE_BACKGROUND,
|
||||
GRAPHIC_SELECT_MUSIC_BACKGROUND,
|
||||
GRAPHIC_RESULT_BACKGROUND,
|
||||
GRAPHIC_SELECT_STYLE_TOP_EDGE,
|
||||
GRAPHIC_SELECT_MUSIC_TOP_EDGE,
|
||||
GRAPHIC_GAME_OPTIONS_TOP_EDGE,
|
||||
GRAPHIC_GRAPHIC_OPTIONS_TOP_EDGE,
|
||||
GRAPHIC_PLAYER_OPTIONS_TOP_EDGE,
|
||||
GRAPHIC_SONG_OPTIONS_TOP_EDGE,
|
||||
GRAPHIC_RESULT_TOP_EDGE,
|
||||
GRAPHIC_FALLBACK_BANNER,
|
||||
GRAPHIC_FALLBACK_BACKGROUND,
|
||||
GRAPHIC_COLOR_ARROW_GRAY_PART,
|
||||
GRAPHIC_COLOR_ARROW_COLOR_PART,
|
||||
GRAPHIC_GHOST_ARROW,
|
||||
GRAPHIC_BRIGHT_GHOST_ARROW,
|
||||
GRAPHIC_HOLD_GHOST_ARROW,
|
||||
GRAPHIC_GRAY_ARROW,
|
||||
GRAPHIC_JUDGEMENT,
|
||||
GRAPHIC_MENU_BOTTOM_EDGE,
|
||||
GRAPHIC_SCORE_FRAME,
|
||||
GRAPHIC_LIFEMETER_FRAME,
|
||||
GRAPHIC_LIFEMETER_PILLS,
|
||||
GRAPHIC_COMBO,
|
||||
GRAPHIC_CLOSING_STAR,
|
||||
GRAPHIC_OPENING_STAR,
|
||||
GRAPHIC_CAUTION,
|
||||
GRAPHIC_READY,
|
||||
GRAPHIC_HERE_WE_GO,
|
||||
GRAPHIC_CLEARED,
|
||||
GRAPHIC_FAILED,
|
||||
GRAPHIC_GRADES,
|
||||
GRAPHIC_KEEP_ALIVE,
|
||||
GRAPHIC_DANCER_P1,
|
||||
GRAPHIC_DANCER_P2,
|
||||
GRAPHIC_PAD_SINGLE,
|
||||
GRAPHIC_PAD_DOUBLE,
|
||||
GRAPHIC_PAD_SOLO,
|
||||
GRAPHIC_STYLE_ICONS,
|
||||
GRAPHIC_MUSIC_SELECTION_HIGHLIGHT,
|
||||
GRAPHIC_STEPS_DESCRIPTION,
|
||||
GRAPHIC_SECTION_BACKGROUND,
|
||||
GRAPHIC_MUSIC_SORT_ICONS,
|
||||
GRAPHIC_MUSIC_STATUS_ICONS,
|
||||
GRAPHIC_DANGER_TEXT,
|
||||
GRAPHIC_DANGER_BACKGROUND,
|
||||
GRAPHIC_ARROWS_LEFT,
|
||||
GRAPHIC_ARROWS_RIGHT,
|
||||
GRAPHIC_EDIT_BACKGROUND,
|
||||
GRAPHIC_EDIT_SNAP_INDICATOR,
|
||||
GRAPHIC_GAME_OPTIONS_BACKGROUND,
|
||||
GRAPHIC_GRAPHIC_OPTIONS_BACKGROUND,
|
||||
GRAPHIC_PLAYER_OPTIONS_BACKGROUND,
|
||||
GRAPHIC_SONG_OPTIONS_BACKGROUND,
|
||||
GRAPHIC_TITLE_MENU_LOGO,
|
||||
GRAPHIC_SYNCHRONIZE_BACKGROUND,
|
||||
GRAPHIC_SYNCHRONIZE_TOP_EDGE,
|
||||
GRAPHIC_TITLE_MENU_LOGO,
|
||||
GRAPHIC_TITLE_MENU_HELP,
|
||||
GRAPHIC_SELECT_DIFFICULTY_BACKGROUND,
|
||||
GRAPHIC_SELECT_DIFFICULTY_TOP_EDGE,
|
||||
GRAPHIC_SELECT_DIFFICULTY_EXPLANATION,
|
||||
GRAPHIC_SELECT_DIFFICULTY_EASY,
|
||||
GRAPHIC_SELECT_DIFFICULTY_MEDIUM,
|
||||
GRAPHIC_SELECT_DIFFICULTY_HARD,
|
||||
GRAPHIC_ARROWS_LEFT,
|
||||
GRAPHIC_ARROWS_RIGHT,
|
||||
GRAPHIC_CAUTION,
|
||||
GRAPHIC_CLEARED,
|
||||
GRAPHIC_CLOSING_STAR,
|
||||
GRAPHIC_COMBO,
|
||||
GRAPHIC_DANCER_P1,
|
||||
GRAPHIC_DANCER_P2,
|
||||
GRAPHIC_DANGER_BACKGROUND,
|
||||
GRAPHIC_DANGER_TEXT,
|
||||
GRAPHIC_EDIT_BACKGROUND,
|
||||
GRAPHIC_EDIT_SNAP_INDICATOR,
|
||||
GRAPHIC_FAILED,
|
||||
GRAPHIC_FALLBACK_BACKGROUND,
|
||||
GRAPHIC_FALLBACK_BANNER,
|
||||
GRAPHIC_GAME_OPTIONS_BACKGROUND,
|
||||
GRAPHIC_GAME_OPTIONS_TOP_EDGE,
|
||||
GRAPHIC_GRADES,
|
||||
GRAPHIC_GRAPHIC_OPTIONS_BACKGROUND,
|
||||
GRAPHIC_GRAPHIC_OPTIONS_TOP_EDGE,
|
||||
GRAPHIC_HERE_WE_GO,
|
||||
GRAPHIC_JUDGEMENT,
|
||||
GRAPHIC_KEEP_ALIVE,
|
||||
GRAPHIC_LIFEMETER_FRAME,
|
||||
GRAPHIC_LIFEMETER_PILLS,
|
||||
GRAPHIC_MENU_BOTTOM_EDGE,
|
||||
GRAPHIC_MUSIC_SELECTION_HIGHLIGHT,
|
||||
GRAPHIC_MUSIC_SORT_ICONS,
|
||||
GRAPHIC_MUSIC_STATUS_ICONS,
|
||||
GRAPHIC_OPENING_STAR,
|
||||
GRAPHIC_PAD_DOUBLE,
|
||||
GRAPHIC_PAD_SINGLE,
|
||||
GRAPHIC_PAD_SOLO,
|
||||
GRAPHIC_PLAYER_OPTIONS_BACKGROUND,
|
||||
GRAPHIC_PLAYER_OPTIONS_TOP_EDGE,
|
||||
GRAPHIC_READY,
|
||||
GRAPHIC_RESULT_BACKGROUND,
|
||||
GRAPHIC_RESULT_TOP_EDGE,
|
||||
GRAPHIC_SCORE_FRAME,
|
||||
GRAPHIC_SECTION_BACKGROUND,
|
||||
GRAPHIC_SELECT_DIFFICULTY_ARROW,
|
||||
GRAPHIC_SELECT_DIFFICULTY_BACKGROUND,
|
||||
GRAPHIC_SELECT_DIFFICULTY_EASY_HEADER,
|
||||
GRAPHIC_SELECT_DIFFICULTY_EASY_PICTURE,
|
||||
GRAPHIC_SELECT_DIFFICULTY_EXPLANATION,
|
||||
GRAPHIC_SELECT_DIFFICULTY_HARD_HEADER,
|
||||
GRAPHIC_SELECT_DIFFICULTY_HARD_PICTURE,
|
||||
GRAPHIC_SELECT_DIFFICULTY_MEDIUM_HEADER,
|
||||
GRAPHIC_SELECT_DIFFICULTY_MEDIUM_PICTURE,
|
||||
GRAPHIC_SELECT_DIFFICULTY_OK,
|
||||
GRAPHIC_SELECT_DIFFICULTY_TOP_EDGE,
|
||||
GRAPHIC_SELECT_MUSIC_BACKGROUND,
|
||||
GRAPHIC_SELECT_MUSIC_INFO_FRAME,
|
||||
GRAPHIC_SELECT_MUSIC_RADAR,
|
||||
GRAPHIC_SELECT_MUSIC_SCORE_FRAME,
|
||||
GRAPHIC_SELECT_MUSIC_TOP_EDGE,
|
||||
GRAPHIC_SELECT_STYLE_BACKGROUND,
|
||||
GRAPHIC_SELECT_STYLE_TOP_EDGE,
|
||||
GRAPHIC_SONG_OPTIONS_BACKGROUND,
|
||||
GRAPHIC_SONG_OPTIONS_TOP_EDGE,
|
||||
GRAPHIC_STEPS_DESCRIPTION,
|
||||
GRAPHIC_STYLE_ICONS,
|
||||
|
||||
SOUND_FAILED,
|
||||
SOUND_ASSIST,
|
||||
@@ -104,6 +100,7 @@ enum ThemeElement {
|
||||
SOUND_INVALID,
|
||||
SOUND_EDIT_CHANGE_LINE,
|
||||
SOUND_EDIT_CHANGE_SNAP,
|
||||
SOUND_SELECT_DIFFICULTY_CHANGE,
|
||||
|
||||
FONT_BOLD,
|
||||
FONT_COMBO_NUMBERS,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "stdafx.h"
|
||||
/*
|
||||
-----------------------------------------------------------------------------
|
||||
File: TransitionStarWipe.cpp
|
||||
Class: TransitionKeepAlive
|
||||
|
||||
Desc: Black bands (horizontal window blinds) gradually close.
|
||||
Desc: See header.
|
||||
|
||||
Copyright (c) 2001 Chris Danford. All rights reserved.
|
||||
-----------------------------------------------------------------------------
|
||||
@@ -16,8 +16,12 @@
|
||||
#include "ThemeManager.h"
|
||||
|
||||
|
||||
const float KEEP_ALIVE_TRANSITION_TIME = 1.0f;
|
||||
|
||||
TransitionKeepAlive::TransitionKeepAlive()
|
||||
{
|
||||
this->SetTransitionTime( KEEP_ALIVE_TRANSITION_TIME );
|
||||
|
||||
m_sprLogo.Load( THEME->GetPathTo(GRAPHIC_KEEP_ALIVE) );
|
||||
m_sprLogo.SetXY( CENTER_X, CENTER_Y );
|
||||
}
|
||||
@@ -33,8 +37,13 @@ void TransitionKeepAlive::Update( float fDeltaTime )
|
||||
|
||||
void TransitionKeepAlive::RenderPrimitives()
|
||||
{
|
||||
const float fPercentClosed = 1 - this->GetPercentageOpen();
|
||||
m_sprLogo.SetDiffuseColor( D3DXCOLOR(1,1,1,fPercentClosed) );
|
||||
float fPercentClosed = 1 - this->GetPercentageOpen();
|
||||
fPercentClosed = min( 1, fPercentClosed*2 );
|
||||
const float fPercentColor = fPercentClosed;
|
||||
const float fPercentAlpha = min( fPercentClosed * 2, 1 );
|
||||
|
||||
m_sprLogo.SetDiffuseColor( D3DXCOLOR(fPercentColor,fPercentColor,fPercentColor,fPercentAlpha) );
|
||||
m_sprLogo.SetZoomY( fPercentClosed );
|
||||
if( fPercentClosed > 0 )
|
||||
m_sprLogo.Draw();
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
-----------------------------------------------------------------------------
|
||||
File: TransitionKeepAlive.cpp
|
||||
Class: TransitionKeepAlive
|
||||
|
||||
Desc: Fades out or in.
|
||||
Desc: The transition between menu screens. "Let's Move On"
|
||||
|
||||
Copyright (c) 2001 Chris Danford. All rights reserved.
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user