Files
itgmania212121/stepmania/src/ArrowEffects.cpp
T

611 lines
21 KiB
C++
Raw Normal View History

2003-02-16 04:01:45 +00:00
#include "global.h"
2002-02-24 10:31:20 +00:00
#include "ArrowEffects.h"
2003-08-03 00:13:55 +00:00
#include "Steps.h"
2002-05-01 19:14:55 +00:00
#include "GameConstantsAndTypes.h"
2002-04-16 17:31:00 +00:00
#include "GameManager.h"
2002-07-27 19:29:51 +00:00
#include "RageException.h"
#include "RageTimer.h"
#include "NoteDisplay.h"
2003-04-22 12:13:36 +00:00
#include "song.h"
2003-07-04 18:03:20 +00:00
#include "RageMath.h"
#include "ScreenDimensions.h"
#include "PlayerState.h"
#include "GameState.h"
#include "Style.h"
#include <float.h>
2002-02-24 10:31:20 +00:00
2003-09-04 04:57:54 +00:00
const float ARROW_SPACING = ARROW_SIZE;// + 2;
static float GetNoteFieldHeight( const PlayerState* pPlayerState )
2004-02-29 19:21:16 +00:00
{
return SCREEN_HEIGHT + fabsf(pPlayerState->m_CurrentPlayerOptions.m_fPerspectiveTilt)*200;
2004-02-29 19:21:16 +00:00
}
namespace
{
float g_fExpandSeconds = 0;
struct PerPlayerData
{
float m_fMinTornadoX[MAX_COLS_PER_PLAYER];
float m_fMaxTornadoX[MAX_COLS_PER_PLAYER];
2005-10-23 07:50:16 +00:00
float m_fInvertDistance[MAX_COLS_PER_PLAYER];
float m_fBeatFactor;
};
PerPlayerData g_EffectData[NUM_PLAYERS];
};
void ArrowEffects::Update()
{
const Style* pStyle = GAMESTATE->GetCurrentStyle();
{
static float fLastTime = 0;
float fTime = RageTimer::GetTimeSinceStartFast();
if( !GAMESTATE->m_bFreeze )
{
g_fExpandSeconds += fTime - fLastTime;
g_fExpandSeconds = fmodf( g_fExpandSeconds, PI*2 );
}
fLastTime = fTime;
}
FOREACH_PlayerNumber( pn )
{
const Style::ColumnInfo* pCols = pStyle->m_ColumnInfo[pn];
PerPlayerData &data = g_EffectData[pn];
//
// Update Tornado
//
for( int iColNum = 0; iColNum < MAX_COLS_PER_PLAYER; ++iColNum )
{
// TRICKY: Tornado is very unplayable in doubles, so use a smaller
// tornado width if there are many columns
bool bWideField = pStyle->m_iColsPerPlayer > 4;
int iTornadoWidth = bWideField ? 2 : 3;
int iStartCol = iColNum - iTornadoWidth;
int iEndCol = iColNum + iTornadoWidth;
CLAMP( iStartCol, 0, pStyle->m_iColsPerPlayer-1 );
CLAMP( iEndCol, 0, pStyle->m_iColsPerPlayer-1 );
data.m_fMinTornadoX[iColNum] = FLT_MAX;
data.m_fMaxTornadoX[iColNum] = FLT_MIN;
for( int i=iStartCol; i<=iEndCol; i++ )
{
data.m_fMinTornadoX[iColNum] = min( data.m_fMinTornadoX[iColNum], pCols[i].fXOffset );
data.m_fMaxTornadoX[iColNum] = max( data.m_fMaxTornadoX[iColNum], pCols[i].fXOffset );
}
}
//
// Update Invert
//
2005-10-23 07:50:16 +00:00
for( int iColNum = 0; iColNum < MAX_COLS_PER_PLAYER; ++iColNum )
{
const int iNumCols = pStyle->m_iColsPerPlayer;
const int iNumSides = pStyle->m_StyleType==ONE_PLAYER_TWO_SIDES ? 2 : 1;
const int iNumColsPerSide = iNumCols / iNumSides;
const int iSideIndex = iColNum / iNumColsPerSide;
const int iColOnSide = iColNum % iNumColsPerSide;
const int iColLeftOfMiddle = (iNumColsPerSide-1)/2;
const int iColRightOfMiddle = (iNumColsPerSide+1)/2;
int iFirstColOnSide = -1;
int iLastColOnSide = -1;
if( iColOnSide <= iColLeftOfMiddle )
{
iFirstColOnSide = 0;
iLastColOnSide = iColLeftOfMiddle;
}
else if( iColOnSide >= iColRightOfMiddle )
{
iFirstColOnSide = iColRightOfMiddle;
iLastColOnSide = iNumColsPerSide-1;
}
else
{
iFirstColOnSide = iColOnSide/2;
iLastColOnSide = iColOnSide/2;
}
// mirror
const int iNewColOnSide = SCALE( iColOnSide, iFirstColOnSide, iLastColOnSide, iLastColOnSide, iFirstColOnSide );
const int iNewCol = iSideIndex*iNumColsPerSide + iNewColOnSide;
const float fOldPixelOffset = pCols[iColNum].fXOffset;
const float fNewPixelOffset = pCols[iNewCol].fXOffset;
2005-10-23 07:50:16 +00:00
data.m_fInvertDistance[iColNum] = fNewPixelOffset - fOldPixelOffset;
}
//
// Update Beat
//
{
float fAccelTime = 0.2f, fTotalTime = 0.5f;
/* If the song is really fast, slow down the rate, but speed up the
* acceleration to compensate or it'll look weird. */
const float fBPM = GAMESTATE->m_fCurBPS * 60;
const float fDiv = max(1.0f, truncf( fBPM / 150.0f ));
fAccelTime /= fDiv;
fTotalTime /= fDiv;
float fBeat = GAMESTATE->m_fSongBeat + fAccelTime;
fBeat /= fDiv;
const bool bEvenBeat = ( int(fBeat) % 2 ) != 0;
data.m_fBeatFactor = 0;
if( fBeat < 0 )
break;
/* -100.2 -> -0.2 -> 0.2 */
fBeat -= truncf( fBeat );
fBeat += 1;
fBeat -= truncf( fBeat );
if( fBeat >= fTotalTime )
break;
if( fBeat < fAccelTime )
{
data.m_fBeatFactor = SCALE( fBeat, 0.0f, fAccelTime, 0.0f, 1.0f);
data.m_fBeatFactor *= data.m_fBeatFactor;
} else /* fBeat < fTotalTime */ {
data.m_fBeatFactor = SCALE( fBeat, fAccelTime, fTotalTime, 1.0f, 0.0f);
data.m_fBeatFactor = 1 - (1-data.m_fBeatFactor) * (1-data.m_fBeatFactor);
}
if( bEvenBeat )
data.m_fBeatFactor *= -1;
data.m_fBeatFactor *= 20.0f;
} while(0);
}
}
2004-12-11 22:31:21 +00:00
/* For visibility testing: if bAbsolute is false, random modifiers must return the
* minimum possible scroll speed. */
float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float fNoteBeat, float &fPeakYOffsetOut, bool &bIsPastPeakOut, bool bAbsolute )
2002-02-24 10:31:20 +00:00
{
// Default values that are returned if boomerang is off.
fPeakYOffsetOut = FLT_MAX;
bIsPastPeakOut = true;
2004-04-09 04:49:29 +00:00
float fYOffset = 0;
/* Usually, fTimeSpacing is 0 or 1, in which case we use entirely beat spacing or
* entirely time spacing (respectively). Occasionally, we tween between them. */
if( pPlayerState->m_CurrentPlayerOptions.m_fTimeSpacing != 1.0f )
{
float fSongBeat = GAMESTATE->m_fSongBeat;
float fBeatsUntilStep = fNoteBeat - fSongBeat;
2004-04-09 04:49:29 +00:00
float fYOffsetBeatSpacing = fBeatsUntilStep * ARROW_SPACING;
fYOffset += fYOffsetBeatSpacing * (1-pPlayerState->m_CurrentPlayerOptions.m_fTimeSpacing);
}
2004-04-09 04:49:29 +00:00
if( pPlayerState->m_CurrentPlayerOptions.m_fTimeSpacing != 0.0f )
{
float fSongSeconds = GAMESTATE->m_fMusicSeconds;
float fNoteSeconds = GAMESTATE->m_pCurSong->GetElapsedTimeFromBeat(fNoteBeat);
float fSecondsUntilStep = fNoteSeconds - fSongSeconds;
float fBPM = pPlayerState->m_CurrentPlayerOptions.m_fScrollBPM;
float fBPS = fBPM/60.f;
2004-04-09 04:49:29 +00:00
float fYOffsetTimeSpacing = fSecondsUntilStep * fBPS * ARROW_SPACING;
fYOffset += fYOffsetTimeSpacing * pPlayerState->m_CurrentPlayerOptions.m_fTimeSpacing;
}
// don't mess with the arrows after they've crossed 0
if( fYOffset < 0 )
return fYOffset * pPlayerState->m_CurrentPlayerOptions.m_fScrollSpeed;
const float* fAccels = pPlayerState->m_CurrentPlayerOptions.m_fAccels;
//const float* fEffects = pPlayerState->m_CurrentPlayerOptions.m_fEffects;
float fYAdjust = 0; // fill this in depending on PlayerOptions
2005-04-22 08:28:19 +00:00
if( fAccels[PlayerOptions::ACCEL_BOOST] != 0 )
{
float fEffectHeight = GetNoteFieldHeight(pPlayerState);
2004-02-29 19:21:16 +00:00
float fNewYOffset = fYOffset * 1.5f / ((fYOffset+fEffectHeight/1.2f)/fEffectHeight);
float fAccelYAdjust = fAccels[PlayerOptions::ACCEL_BOOST] * (fNewYOffset - fYOffset);
// TRICKY: Clamp this value, or else BOOST+BOOMERANG will draw a ton of arrows on the screen.
CLAMP( fAccelYAdjust, -400.f, 400.f );
fYAdjust += fAccelYAdjust;
}
2005-04-22 08:28:19 +00:00
if( fAccels[PlayerOptions::ACCEL_BRAKE] != 0 )
{
float fEffectHeight = GetNoteFieldHeight(pPlayerState);
2004-02-29 19:21:16 +00:00
float fScale = SCALE( fYOffset, 0.f, fEffectHeight, 0, 1.f );
2003-09-16 07:21:50 +00:00
float fNewYOffset = fYOffset * fScale;
2004-02-29 19:21:16 +00:00
float fBrakeYAdjust = fAccels[PlayerOptions::ACCEL_BRAKE] * (fNewYOffset - fYOffset);
// TRICKY: Clamp this value the same way as BOOST so that in BOOST+BRAKE, BRAKE doesn't overpower BOOST
CLAMP( fBrakeYAdjust, -400.f, 400.f );
fYAdjust += fBrakeYAdjust;
}
2005-04-22 08:28:19 +00:00
if( fAccels[PlayerOptions::ACCEL_WAVE] != 0 )
fYAdjust += fAccels[PlayerOptions::ACCEL_WAVE] * 20.0f*RageFastSin( fYOffset/38.0f );
2004-02-29 19:21:16 +00:00
fYOffset += fYAdjust;
//
// Factor in boomerang
//
2005-04-22 08:28:19 +00:00
if( fAccels[PlayerOptions::ACCEL_BOOMERANG] != 0 )
{
2005-10-25 19:18:48 +00:00
float fPeakAtYOffset = SCREEN_HEIGHT * 0.75f; // zero point of boomerang function
2005-04-07 08:28:13 +00:00
fPeakYOffsetOut = (-1*fPeakAtYOffset*fPeakAtYOffset/SCREEN_HEIGHT) + 1.5f*fPeakAtYOffset;
2005-10-25 19:18:48 +00:00
bIsPastPeakOut = fYOffset < fPeakAtYOffset;
fYOffset = (-1*fYOffset*fYOffset/SCREEN_HEIGHT) + 1.5f*fYOffset;
}
//
// Factor in scroll speed
//
float fScrollSpeed = pPlayerState->m_CurrentPlayerOptions.m_fScrollSpeed;
if( pPlayerState->m_CurrentPlayerOptions.m_fRandomSpeed > 0 && !bAbsolute )
{
int seed = GAMESTATE->m_iStageSeed + ( BeatToNoteRow( fNoteBeat ) << 8 ) + (iCol * 100);
2004-12-11 12:31:17 +00:00
/* Temporary hack: the first call to RandomFloat isn't "random"; it takes an extra
* call to get the RNG rolling. */
RandomFloat( seed );
float fRandom = RandomFloat( seed );
2004-12-11 12:11:36 +00:00
/* Random speed always increases speed: a random speed of 10 indicates [1,11].
* This keeps it consistent with other mods: 0 means no effect. */
2004-12-11 11:58:56 +00:00
fScrollSpeed *=
2004-12-11 12:11:36 +00:00
SCALE( fRandom,
0.0f, 1.0f,
1.0f, pPlayerState->m_CurrentPlayerOptions.m_fRandomSpeed + 1.0f );
}
2004-02-29 19:21:16 +00:00
2005-04-22 08:28:19 +00:00
if( fAccels[PlayerOptions::ACCEL_EXPAND] != 0 )
2003-01-25 11:05:12 +00:00
{
float fExpandMultiplier = SCALE( RageFastCos(g_fExpandSeconds*3), -1, 1, 0.75f, 1.75f );
2004-03-14 19:55:17 +00:00
fScrollSpeed *= SCALE( fAccels[PlayerOptions::ACCEL_EXPAND], 0.f, 1.f, 1.f, fExpandMultiplier );
2003-01-25 11:05:12 +00:00
}
2002-02-24 10:31:20 +00:00
2004-03-14 19:55:17 +00:00
fYOffset *= fScrollSpeed;
fPeakYOffsetOut *= fScrollSpeed;
2004-03-14 19:55:17 +00:00
return fYOffset;
2003-09-26 03:21:53 +00:00
}
static void ArrowGetReverseShiftAndScale( const PlayerState* pPlayerState, int iCol, float fYReverseOffsetPixels, float &fShiftOut, float &fScaleOut )
2003-09-30 03:14:09 +00:00
{
2006-04-05 02:59:16 +00:00
/* XXX: Hack: we need to scale the reverse shift by the zoom. */
float fTinyPercent = pPlayerState->m_CurrentPlayerOptions.m_fEffects[PlayerOptions::EFFECT_TINY];
float fZoom = 1 - fTinyPercent*0.5f;
// don't divide by 0
if( fabsf(fZoom) < 0.01 )
fZoom = 0.01f;
float fPercentReverse = pPlayerState->m_CurrentPlayerOptions.GetReversePercentForColumn(iCol);
2006-04-05 02:59:16 +00:00
fShiftOut = SCALE( fPercentReverse, 0.f, 1.f, -fYReverseOffsetPixels/fZoom/2, fYReverseOffsetPixels/fZoom/2 );
float fPercentCentered = pPlayerState->m_CurrentPlayerOptions.m_fScrolls[PlayerOptions::SCROLL_CENTERED];
2005-10-23 04:11:27 +00:00
fShiftOut = SCALE( fPercentCentered, 0.f, 1.f, fShiftOut, 0.0f );
2004-02-23 07:44:11 +00:00
2005-10-23 04:14:06 +00:00
fScaleOut = SCALE( fPercentReverse, 0.f, 1.f, 1.f, -1.f );
2003-09-30 03:14:09 +00:00
}
float ArrowEffects::GetYPos( const PlayerState* pPlayerState, int iCol, float fYOffset, float fYReverseOffsetPixels, bool WithReverse )
2003-09-30 03:14:09 +00:00
{
float f = fYOffset;
if( WithReverse )
{
float fShift, fScale;
ArrowGetReverseShiftAndScale( pPlayerState, iCol, fYReverseOffsetPixels, fShift, fScale );
2003-09-30 03:14:09 +00:00
f *= fScale;
f += fShift;
}
2003-09-26 03:21:53 +00:00
const float* fEffects = pPlayerState->m_CurrentPlayerOptions.m_fEffects;
2003-09-26 03:21:53 +00:00
2005-04-22 08:28:19 +00:00
if( fEffects[PlayerOptions::EFFECT_TIPSY] != 0 )
f += fEffects[PlayerOptions::EFFECT_TIPSY] * ( RageFastCos( RageTimer::GetTimeSinceStartFast()*1.2f + iCol*1.8f) * ARROW_SIZE*0.4f );
2003-09-26 03:21:53 +00:00
return f;
}
float ArrowEffects::GetYOffsetFromYPos( const PlayerState* pPlayerState, int iCol, float YPos, float fYReverseOffsetPixels )
2003-09-30 03:14:09 +00:00
{
float f = YPos;
const float* fEffects = pPlayerState->m_CurrentPlayerOptions.m_fEffects;
2005-04-22 08:28:19 +00:00
if( fEffects[PlayerOptions::EFFECT_TIPSY] != 0 )
f -= fEffects[PlayerOptions::EFFECT_TIPSY] * ( RageFastCos( RageTimer::GetTimeSinceStartFast()*1.2f + iCol*2.f) * ARROW_SIZE*0.4f );
2003-09-30 03:14:09 +00:00
float fShift, fScale;
ArrowGetReverseShiftAndScale( pPlayerState, iCol, fYReverseOffsetPixels, fShift, fScale );
2003-09-30 03:14:09 +00:00
f -= fShift;
if( fScale )
f /= fScale;
return f;
}
2003-09-26 03:21:53 +00:00
float ArrowEffects::GetXPos( const PlayerState* pPlayerState, int iColNum, float fYOffset )
2002-02-24 10:31:20 +00:00
{
2005-05-05 21:40:54 +00:00
float fPixelOffsetFromCenter = 0; // fill this in below
2002-02-24 10:31:20 +00:00
2005-05-05 21:40:54 +00:00
const Style* pStyle = GAMESTATE->GetCurrentStyle();
const float* fEffects = pPlayerState->m_CurrentPlayerOptions.m_fEffects;
2005-10-23 02:40:40 +00:00
// TODO: Don't index by PlayerNumber.
const Style::ColumnInfo* pCols = pStyle->m_ColumnInfo[pPlayerState->m_PlayerNumber];
PerPlayerData &data = g_EffectData[pPlayerState->m_PlayerNumber];
2005-10-23 02:40:40 +00:00
2005-04-22 08:28:19 +00:00
if( fEffects[PlayerOptions::EFFECT_TORNADO] != 0 )
{
2005-10-23 02:40:40 +00:00
const float fRealPixelOffset = pCols[iColNum].fXOffset;
const float fPositionBetween = SCALE( fRealPixelOffset, data.m_fMinTornadoX[iColNum], data.m_fMaxTornadoX[iColNum], -1, 1 );
float fRads = acosf( fPositionBetween );
2003-09-30 03:14:09 +00:00
fRads += fYOffset * 6 / SCREEN_HEIGHT;
const float fAdjustedPixelOffset = SCALE( RageFastCos(fRads), -1, 1, data.m_fMinTornadoX[iColNum], data.m_fMaxTornadoX[iColNum] );
2003-04-02 21:58:27 +00:00
2003-10-24 07:40:42 +00:00
fPixelOffsetFromCenter += (fAdjustedPixelOffset - fRealPixelOffset) * fEffects[PlayerOptions::EFFECT_TORNADO];
}
2005-04-22 08:28:19 +00:00
if( fEffects[PlayerOptions::EFFECT_DRUNK] != 0 )
fPixelOffsetFromCenter += fEffects[PlayerOptions::EFFECT_DRUNK] * ( RageFastCos( RageTimer::GetTimeSinceStartFast() + iColNum*0.2f + fYOffset*10/SCREEN_HEIGHT) * ARROW_SIZE*0.5f );
2005-04-22 08:28:19 +00:00
if( fEffects[PlayerOptions::EFFECT_FLIP] != 0 )
2003-05-17 21:39:32 +00:00
{
2005-10-23 02:48:03 +00:00
const int iFirstCol = 0;
const int iLastCol = pStyle->m_iColsPerPlayer-1;
2005-05-05 21:40:54 +00:00
const int iNewCol = SCALE( iColNum, iFirstCol, iLastCol, iLastCol, iFirstCol );
2005-10-23 02:40:40 +00:00
const float fOldPixelOffset = pCols[iColNum].fXOffset;
const float fNewPixelOffset = pCols[iNewCol].fXOffset;
2005-05-05 21:40:54 +00:00
const float fDistance = fNewPixelOffset - fOldPixelOffset;
2003-05-17 21:39:32 +00:00
fPixelOffsetFromCenter += fDistance * fEffects[PlayerOptions::EFFECT_FLIP];
}
2005-05-05 21:40:54 +00:00
if( fEffects[PlayerOptions::EFFECT_INVERT] != 0 )
2005-10-23 07:50:16 +00:00
fPixelOffsetFromCenter += data.m_fInvertDistance[iColNum] * fEffects[PlayerOptions::EFFECT_INVERT];
2005-04-22 08:28:19 +00:00
if( fEffects[PlayerOptions::EFFECT_BEAT] != 0 )
2003-07-09 10:40:34 +00:00
do {
const float fShift = data.m_fBeatFactor*RageFastSin( fYOffset / 15.0f + PI/2.0f );
2003-07-09 10:40:34 +00:00
fPixelOffsetFromCenter += fEffects[PlayerOptions::EFFECT_BEAT] * fShift;
} while(0);
fPixelOffsetFromCenter += pCols[iColNum].fXOffset;
if( fEffects[PlayerOptions::EFFECT_MINI] != 0 )
{
/* Allow Mini to pull tracks together, but not to push them apart. */
float fMiniPercent = fEffects[PlayerOptions::EFFECT_MINI];
fMiniPercent = min( powf(0.5f, fMiniPercent), 1.0f );
fPixelOffsetFromCenter *= fMiniPercent;
}
2002-02-24 10:31:20 +00:00
return fPixelOffsetFromCenter;
}
float ArrowEffects::GetRotation( const PlayerState* pPlayerState, float fNoteBeat )
2002-02-24 10:31:20 +00:00
{
2005-04-22 08:28:19 +00:00
if( pPlayerState->m_CurrentPlayerOptions.m_fEffects[PlayerOptions::EFFECT_DIZZY] != 0 )
2003-01-25 11:05:12 +00:00
{
2003-11-18 00:50:06 +00:00
const float fSongBeat = GAMESTATE->m_fSongBeat;
float fDizzyRotation = fNoteBeat - fSongBeat;
fDizzyRotation *= pPlayerState->m_CurrentPlayerOptions.m_fEffects[PlayerOptions::EFFECT_DIZZY];
fDizzyRotation = fmodf( fDizzyRotation, 2*PI );
2003-04-07 21:31:45 +00:00
fDizzyRotation *= 180/PI;
2003-11-18 00:50:06 +00:00
return fDizzyRotation;
2003-01-25 11:05:12 +00:00
}
else
return 0;
2002-02-24 10:31:20 +00:00
}
2004-02-29 08:59:12 +00:00
#define CENTER_LINE_Y 160 // from fYOffset == 0
#define FADE_DIST_Y 40
static float GetCenterLine( const PlayerState* pPlayerState )
2002-02-24 10:31:20 +00:00
{
2006-04-05 02:59:16 +00:00
/* Another mini hack: if EFFECT_MINI is on, then our center line is at eg. 320,
* not 160. */
const float fMiniPercent = pPlayerState->m_CurrentPlayerOptions.m_fEffects[PlayerOptions::EFFECT_TINY];
const float fZoom = 1 - fMiniPercent*0.5f;
return CENTER_LINE_Y / fZoom;
2004-02-29 08:59:12 +00:00
}
static float GetHiddenSudden( const PlayerState* pPlayerState )
2004-02-29 08:59:12 +00:00
{
const float* fAppearances = pPlayerState->m_CurrentPlayerOptions.m_fAppearances;
2004-02-29 08:59:12 +00:00
return fAppearances[PlayerOptions::APPEARANCE_HIDDEN] *
fAppearances[PlayerOptions::APPEARANCE_SUDDEN];
}
//
// -gray arrows-
//
// ...invisible...
// -hidden end line-
// -hidden start line-
// ...visible...
// -sudden end line-
// -sudden start line-
// ...invisible...
//
// TRICKY: We fudge hidden and sudden to be farther apart if they're both on.
static float GetHiddenEndLine( const PlayerState* pPlayerState )
2004-02-29 08:59:12 +00:00
{
2005-04-20 08:54:12 +00:00
return GetCenterLine( pPlayerState ) +
FADE_DIST_Y * SCALE( GetHiddenSudden(pPlayerState), 0.f, 1.f, -1.0f, -1.25f ) +
GetCenterLine( pPlayerState ) * pPlayerState->m_CurrentPlayerOptions.m_fAppearances[PlayerOptions::APPEARANCE_HIDDEN_OFFSET];
2004-02-29 08:59:12 +00:00
}
static float GetHiddenStartLine( const PlayerState* pPlayerState )
2004-02-29 08:59:12 +00:00
{
2005-04-20 08:54:12 +00:00
return GetCenterLine( pPlayerState ) +
FADE_DIST_Y * SCALE( GetHiddenSudden(pPlayerState), 0.f, 1.f, +0.0f, -0.25f ) +
GetCenterLine( pPlayerState ) * pPlayerState->m_CurrentPlayerOptions.m_fAppearances[PlayerOptions::APPEARANCE_HIDDEN_OFFSET];
2004-02-29 08:59:12 +00:00
}
static float GetSuddenEndLine( const PlayerState* pPlayerState )
2004-02-29 08:59:12 +00:00
{
2005-04-20 08:54:12 +00:00
return GetCenterLine( pPlayerState ) +
FADE_DIST_Y * SCALE( GetHiddenSudden(pPlayerState), 0.f, 1.f, -0.0f, +0.25f ) +
GetCenterLine( pPlayerState ) * pPlayerState->m_CurrentPlayerOptions.m_fAppearances[PlayerOptions::APPEARANCE_SUDDEN_OFFSET];
2004-02-29 08:59:12 +00:00
}
static float GetSuddenStartLine( const PlayerState* pPlayerState )
2004-02-29 08:59:12 +00:00
{
2005-04-20 08:54:12 +00:00
return GetCenterLine( pPlayerState ) +
FADE_DIST_Y * SCALE( GetHiddenSudden(pPlayerState), 0.f, 1.f, +1.0f, +1.25f ) +
GetCenterLine( pPlayerState ) * pPlayerState->m_CurrentPlayerOptions.m_fAppearances[PlayerOptions::APPEARANCE_SUDDEN_OFFSET];
2003-09-30 03:14:09 +00:00
}
2003-09-30 03:14:09 +00:00
// used by ArrowGetAlpha and ArrowGetGlow below
float ArrowGetPercentVisible( const PlayerState* pPlayerState, int iCol, float fYOffset, float fYReverseOffsetPixels )
2003-09-30 03:14:09 +00:00
{
/* Get the YPos without reverse (that is, factor in EFFECT_TIPSY). */
float fYPos = ArrowEffects::GetYPos( pPlayerState, iCol, fYOffset, fYReverseOffsetPixels, false );
2003-09-09 01:32:32 +00:00
const float fDistFromCenterLine = fYPos - GetCenterLine( pPlayerState );
2003-04-17 21:44:33 +00:00
if( fYPos < 0 ) // past Gray Arrows
return 1; // totally visible
const float* fAppearances = pPlayerState->m_CurrentPlayerOptions.m_fAppearances;
float fVisibleAdjust = 0;
2005-04-22 08:28:19 +00:00
if( fAppearances[PlayerOptions::APPEARANCE_HIDDEN] != 0 )
2004-02-29 08:59:12 +00:00
{
float fHiddenVisibleAdjust = SCALE( fYPos, GetHiddenStartLine(pPlayerState), GetHiddenEndLine(pPlayerState), 0, -1 );
2004-02-29 08:59:12 +00:00
CLAMP( fHiddenVisibleAdjust, -1, 0 );
fVisibleAdjust += fAppearances[PlayerOptions::APPEARANCE_HIDDEN] * fHiddenVisibleAdjust;
}
2005-04-22 08:28:19 +00:00
if( fAppearances[PlayerOptions::APPEARANCE_SUDDEN] != 0 )
2003-10-01 21:46:00 +00:00
{
float fSuddenVisibleAdjust = SCALE( fYPos, GetSuddenStartLine(pPlayerState), GetSuddenEndLine(pPlayerState), -1, 0 );
2004-02-29 08:59:12 +00:00
CLAMP( fSuddenVisibleAdjust, -1, 0 );
fVisibleAdjust += fAppearances[PlayerOptions::APPEARANCE_SUDDEN] * fSuddenVisibleAdjust;
2003-10-01 21:46:00 +00:00
}
2005-04-22 08:28:19 +00:00
if( fAppearances[PlayerOptions::APPEARANCE_STEALTH] != 0 )
fVisibleAdjust -= fAppearances[PlayerOptions::APPEARANCE_STEALTH];
2005-04-22 08:28:19 +00:00
if( fAppearances[PlayerOptions::APPEARANCE_BLINK] != 0 )
2003-04-21 00:12:42 +00:00
{
float f = RageFastSin(RageTimer::GetTimeSinceStartFast()*10);
f = Quantize( f, 0.3333f );
2003-04-21 00:12:42 +00:00
fVisibleAdjust += SCALE( f, 0, 1, -1, 0 );
}
2005-04-22 08:28:19 +00:00
if( fAppearances[PlayerOptions::APPEARANCE_RANDOMVANISH] != 0 )
{
2003-09-30 03:59:37 +00:00
const float fRealFadeDist = 80;
fVisibleAdjust += SCALE( fabsf(fDistFromCenterLine), fRealFadeDist, 2*fRealFadeDist, -1, 0 )
* fAppearances[PlayerOptions::APPEARANCE_RANDOMVANISH];
}
2002-02-24 10:31:20 +00:00
return clamp( 1+fVisibleAdjust, 0, 1 );
}
2002-02-24 10:31:20 +00:00
float ArrowEffects::GetAlpha( const PlayerState* pPlayerState, int iCol, float fYOffset, float fPercentFadeToFail, float fYReverseOffsetPixels )
{
float fPercentVisible = ArrowGetPercentVisible(pPlayerState,iCol,fYOffset,fYReverseOffsetPixels);
2002-09-05 03:45:07 +00:00
if( fPercentFadeToFail != -1 )
fPercentVisible = 1 - fPercentFadeToFail;
return (fPercentVisible>0.5f) ? 1.0f : 0.0f;
}
2002-02-24 10:31:20 +00:00
float ArrowEffects::GetGlow( const PlayerState* pPlayerState, int iCol, float fYOffset, float fPercentFadeToFail, float fYReverseOffsetPixels )
{
float fPercentVisible = ArrowGetPercentVisible(pPlayerState,iCol,fYOffset,fYReverseOffsetPixels);
2002-09-05 03:45:07 +00:00
if( fPercentFadeToFail != -1 )
fPercentVisible = 1 - fPercentFadeToFail;
const float fDistFromHalf = fabsf( fPercentVisible - 0.5f );
return SCALE( fDistFromHalf, 0, 0.5f, 1.3f, 0 );
}
2003-02-12 22:05:14 +00:00
float ArrowEffects::GetBrightness( const PlayerState* pPlayerState, float fNoteBeat )
2003-02-12 22:05:14 +00:00
{
if( GAMESTATE->IsEditing() )
2003-02-18 23:15:38 +00:00
return 1;
float fSongBeat = GAMESTATE->m_fSongBeat;
float fBeatsUntilStep = fNoteBeat - fSongBeat;
float fBrightness = SCALE( fBeatsUntilStep, 0, -1, 1.f, 0.f );
2003-02-12 22:05:14 +00:00
CLAMP( fBrightness, 0, 1 );
return fBrightness;
}
2003-07-09 00:49:05 +00:00
float ArrowEffects::GetZPos( const PlayerState* pPlayerState, int iCol, float fYOffset )
2003-07-09 00:49:05 +00:00
{
2003-07-09 01:34:48 +00:00
float fZPos=0;
const float* fEffects = pPlayerState->m_CurrentPlayerOptions.m_fEffects;
2003-07-09 01:34:48 +00:00
2005-04-22 08:28:19 +00:00
if( fEffects[PlayerOptions::EFFECT_BUMPY] != 0 )
fZPos += fEffects[PlayerOptions::EFFECT_BUMPY] * 40*RageFastSin( fYOffset/16.0f );
2003-07-09 01:34:48 +00:00
return fZPos;
}
bool ArrowEffects::NeedZBuffer( const PlayerState* pPlayerState )
2003-07-09 01:34:48 +00:00
{
const float* fEffects = pPlayerState->m_CurrentPlayerOptions.m_fEffects;
2005-04-22 08:28:19 +00:00
if( fEffects[PlayerOptions::EFFECT_BUMPY] != 0 )
2003-07-09 01:34:48 +00:00
return true;
return false;
2003-07-09 00:49:05 +00:00
}
float ArrowEffects::GetZoom( const PlayerState* pPlayerState )
{
float fZoom = 1.0f;
2004-06-28 07:26:00 +00:00
// FIXME: Move the zoom values into Style
if( GAMESTATE->m_pCurStyle->m_bNeedsZoomOutWith2Players &&
(GAMESTATE->GetNumSidesJoined()==2 || GAMESTATE->AnyPlayersAreCpu()) )
fZoom *= 0.6f;
float fMiniPercent = pPlayerState->m_CurrentPlayerOptions.m_fEffects[PlayerOptions::EFFECT_MINI];
2005-10-22 23:31:12 +00:00
if( fMiniPercent != 0 )
{
fMiniPercent = powf( 0.5f, fMiniPercent );
fZoom *= fMiniPercent;
}
return fZoom;
}
2004-06-08 00:08:04 +00:00
/*
* (c) 2001-2004 Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/