2003-02-16 04:01:45 +00:00
#include "global.h"
2002-02-24 10:31:20 +00:00
/*
-----------------------------------------------------------------------------
File: ArrowEffects.cpp
2002-03-19 07:09:49 +00:00
Desc: Functions that return properties of arrows based on StyleDef and PlayerOptions
2002-02-24 10:31:20 +00:00
2002-05-19 01:59:48 +00:00
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
2002-02-24 10:31:20 +00:00
Chris Danford
-----------------------------------------------------------------------------
*/
2002-08-13 23:26:46 +00:00
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-23 01:41:40 +00:00
#include "GameState.h"
2002-07-27 19:29:51 +00:00
#include "RageException.h"
#include "RageTimer.h"
2002-08-13 23:26:46 +00:00
#include "NoteDisplay.h"
2003-04-22 12:13:36 +00:00
#include "song.h"
2002-11-11 04:53:31 +00:00
#include <math.h>
2003-07-04 18:03:20 +00:00
#include "RageMath.h"
2002-02-24 10:31:20 +00:00
2003-09-04 04:57:54 +00:00
const float ARROW_SPACING = ARROW_SIZE ; // + 2;
2003-01-25 11:05:12 +00:00
float g_fExpandSeconds = 0 ;
2003-08-16 23:34:47 +00:00
float ArrowGetYOffset ( PlayerNumber pn , int iCol , float fNoteBeat )
2002-02-24 10:31:20 +00:00
{
2003-04-16 22:48:00 +00:00
float fYOffset ;
2003-04-24 06:16:04 +00:00
if ( ! GAMESTATE -> m_PlayerOptions [ pn ]. m_bTimeSpacing )
2003-04-16 22:48:00 +00:00
{
float fSongBeat = GAMESTATE -> m_fSongBeat ;
float fBeatsUntilStep = fNoteBeat - fSongBeat ;
fYOffset = fBeatsUntilStep * ARROW_SPACING ;
}
else
{
float fSongSeconds = GAMESTATE -> m_fMusicSeconds ;
float fNoteSeconds = GAMESTATE -> m_pCurSong -> GetElapsedTimeFromBeat ( fNoteBeat );
float fSecondsUntilStep = fNoteSeconds - fSongSeconds ;
2003-04-24 06:16:04 +00:00
float fBPM = GAMESTATE -> m_PlayerOptions [ pn ]. m_fScrollBPM ;
2003-04-16 22:48:00 +00:00
float fBPS = fBPM / 60.f ;
fYOffset = fSecondsUntilStep * fBPS * ARROW_SPACING ;
}
2002-08-31 03:04:38 +00:00
2003-02-26 23:26:57 +00:00
// don't mess with the arrows after they've crossed 0
if ( fYOffset < 0 )
return fYOffset ;
const float * fAccels = GAMESTATE -> m_CurrentPlayerOptions [ pn ]. m_fAccels ;
2003-08-31 14:00:14 +00:00
//const float* fEffects = GAMESTATE->m_CurrentPlayerOptions[pn].m_fEffects;
2003-01-25 11:05:12 +00:00
2003-02-26 23:26:57 +00:00
float fYAdjust = 0 ; // fill this in depending on PlayerOptions
if ( fAccels [ PlayerOptions :: ACCEL_BOOST ] > 0 )
{
float fNewYOffset = fYOffset * 1.5f / (( fYOffset + SCREEN_HEIGHT / 1.2f ) / SCREEN_HEIGHT );
fYAdjust += fAccels [ PlayerOptions :: ACCEL_BOOST ] * ( fNewYOffset - fYOffset );
}
2003-04-01 19:31:27 +00:00
if ( fAccels [ PlayerOptions :: ACCEL_BRAKE ] > 0 )
2003-02-26 23:26:57 +00:00
{
float fNewYOffset = fYOffset * SCALE ( fYOffset , 0.f , SCREEN_HEIGHT , 0.25f , 1.5f );
2003-04-01 19:31:27 +00:00
fYAdjust += fAccels [ PlayerOptions :: ACCEL_BRAKE ] * ( fNewYOffset - fYOffset );
2003-02-26 23:26:57 +00:00
}
if ( fAccels [ PlayerOptions :: ACCEL_WAVE ] > 0 )
fYAdjust += fAccels [ PlayerOptions :: ACCEL_WAVE ] * 20.0f * sinf ( fYOffset / 38.0f );
if ( fAccels [ PlayerOptions :: ACCEL_EXPAND ] > 0 )
2003-01-25 11:05:12 +00:00
{
2003-06-17 19:26:16 +00:00
/* Timers can't be global, since they'll be initialized before SDL. */
static RageTimer timerExpand ;
2003-01-25 11:05:12 +00:00
if ( ! GAMESTATE -> m_bFreeze )
2003-06-17 19:26:16 +00:00
g_fExpandSeconds += timerExpand . GetDeltaTime ();
2003-01-25 11:05:12 +00:00
else
2003-06-17 19:26:16 +00:00
timerExpand . GetDeltaTime (); // throw away
2003-02-26 23:26:57 +00:00
fYAdjust += fAccels [ PlayerOptions :: ACCEL_EXPAND ] * ( fYOffset * SCALE ( cosf ( g_fExpandSeconds * 3 ), - 1 , 1 , 0.5f , 1.5f ) - fYOffset );
2003-01-25 11:05:12 +00:00
}
2003-02-26 23:26:57 +00:00
if ( fAccels [ PlayerOptions :: ACCEL_BOOMERANG ] > 0 )
fYAdjust += fAccels [ PlayerOptions :: ACCEL_BOOMERANG ] * ( fYOffset * SCALE ( fYOffset , 0.f , SCREEN_HEIGHT , 1.5f , 0.5f ) - fYOffset );
2002-08-31 03:04:38 +00:00
2003-02-26 23:26:57 +00:00
return fYOffset + fYAdjust ;
2002-02-24 10:31:20 +00:00
}
2002-08-29 01:38:21 +00:00
float ArrowGetXPos ( PlayerNumber pn , int iColNum , float fYPos )
2002-02-24 10:31:20 +00:00
{
2003-04-02 21:58:27 +00:00
float fPixelOffsetFromCenter = 0 ;
2002-02-24 10:31:20 +00:00
2003-02-26 23:26:57 +00:00
const float * fEffects = GAMESTATE -> m_CurrentPlayerOptions [ pn ]. m_fEffects ;
if ( fEffects [ PlayerOptions :: EFFECT_TORNADO ] > 0 )
2002-09-02 21:59:58 +00:00
{
2003-02-19 07:59:00 +00:00
float fMinX , fMaxX ;
2003-04-02 21:58:27 +00:00
GAMESTATE -> GetCurrentStyleDef () -> GetMinAndMaxColX ( pn , fMinX , fMaxX );
2002-09-02 21:59:58 +00:00
2003-05-17 21:39:32 +00:00
const float fRealPixelOffset = GAMESTATE -> GetCurrentStyleDef () -> m_ColumnInfo [ pn ][ iColNum ]. fXOffset ;
const float fPositionBetween = SCALE ( fRealPixelOffset , fMinX , fMaxX , - 1 , 1 );
2002-09-02 21:59:58 +00:00
float fRads = acosf ( fPositionBetween );
fRads += fYPos * 6 / SCREEN_HEIGHT ;
2003-05-17 21:39:32 +00:00
const float fAdjustedPixelOffset = SCALE ( cosf ( fRads ), - 1 , 1 , fMinX , fMaxX );
2003-04-02 21:58:27 +00:00
fPixelOffsetFromCenter = fAdjustedPixelOffset - fRealPixelOffset ;
2002-09-02 21:59:58 +00:00
}
2002-08-31 03:04:38 +00:00
2003-02-26 23:26:57 +00:00
if ( fEffects [ PlayerOptions :: EFFECT_DRUNK ] > 0 )
fPixelOffsetFromCenter += fEffects [ PlayerOptions :: EFFECT_DRUNK ] * ( cosf ( RageTimer :: GetTimeSinceStart () + iColNum * 0.2f + fYPos * 10 / SCREEN_HEIGHT ) * ARROW_SIZE * 0.5f );
if ( fEffects [ PlayerOptions :: EFFECT_FLIP ] > 0 )
2003-05-17 21:39:32 +00:00
{
2003-05-17 21:40:11 +00:00
// fPixelOffsetFromCenter *= SCALE(fEffects[PlayerOptions::EFFECT_FLIP], 0.f, 1.f, 1.f, -1.f);
2003-05-17 21:39:32 +00:00
const float fRealPixelOffset = GAMESTATE -> GetCurrentStyleDef () -> m_ColumnInfo [ pn ][ iColNum ]. fXOffset ;
const float fDistance = - fRealPixelOffset * 2 ;
fPixelOffsetFromCenter += fDistance * fEffects [ PlayerOptions :: EFFECT_FLIP ];
}
2003-02-26 23:26:57 +00:00
2003-07-09 10:40:34 +00:00
if ( fEffects [ PlayerOptions :: EFFECT_BEAT ] > 0 )
do {
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 ;
/* -100.2 -> -0.2 -> 0.2 */
if ( fBeat < 0 )
break ;
fBeat -= truncf ( fBeat );
fBeat += 1 ;
fBeat -= truncf ( fBeat );
if ( fBeat >= fTotalTime )
break ;
float fAmount ;
if ( fBeat < fAccelTime )
{
fAmount = SCALE ( fBeat , 0.0f , fAccelTime , 0.0f , 1.0f );
fAmount *= fAmount ;
} else /* fBeat < fTotalTime */ {
fAmount = SCALE ( fBeat , fAccelTime , fTotalTime , 1.0f , 0.0f );
fAmount = 1 - ( 1 - fAmount ) * ( 1 - fAmount );
}
if ( bEvenBeat )
fAmount *= - 1 ;
const float fShift = 20.0f * fAmount * sinf ( fYPos / 15.0f + PI / 2.0f );
fPixelOffsetFromCenter += fEffects [ PlayerOptions :: EFFECT_BEAT ] * fShift ;
} while ( 0 );
2002-02-24 10:31:20 +00:00
return fPixelOffsetFromCenter ;
}
2003-01-25 11:05:12 +00:00
float ArrowGetRotation ( PlayerNumber pn , float fNoteBeat )
2002-02-24 10:31:20 +00:00
{
2003-02-26 23:26:57 +00:00
if ( GAMESTATE -> m_CurrentPlayerOptions [ pn ]. m_fEffects [ PlayerOptions :: EFFECT_DIZZY ] > 0 )
2003-01-25 11:05:12 +00:00
{
float fSongBeat = GAMESTATE -> m_fSongBeat ;
2003-02-26 23:26:57 +00:00
float fDizzyRotation = fNoteBeat - fSongBeat ;
fDizzyRotation = fmodf ( fDizzyRotation , 2 * PI );
2003-04-07 21:31:45 +00:00
fDizzyRotation *= 180 / PI ;
2003-02-26 23:26:57 +00:00
return fDizzyRotation * GAMESTATE -> m_CurrentPlayerOptions [ pn ]. m_fEffects [ PlayerOptions :: EFFECT_DIZZY ];
2003-01-25 11:05:12 +00:00
}
2003-02-26 23:26:57 +00:00
else
return 0 ;
2002-02-24 10:31:20 +00:00
}
2003-08-16 23:34:47 +00:00
float ArrowGetYPosWithoutReverse ( PlayerNumber pn , int iCol , float fYOffset )
2003-01-25 11:05:12 +00:00
{
2003-04-16 22:48:00 +00:00
float fYPos = fYOffset * GAMESTATE -> m_CurrentPlayerOptions [ pn ]. m_fScrollSpeed ;
return fYPos ;
2003-01-25 11:05:12 +00:00
}
2003-08-16 23:34:47 +00:00
float ArrowGetYPos ( PlayerNumber pn , int iCol , float fYOffset , float fYReverseOffsetPixels )
2002-02-24 10:31:20 +00:00
{
2003-08-16 23:34:47 +00:00
float f = ArrowGetYPosWithoutReverse ( pn , iCol , fYOffset );
2003-08-17 00:15:54 +00:00
f *= SCALE ( GAMESTATE -> m_CurrentPlayerOptions [ pn ]. GetReversePercentForColumn ( iCol ), 0.f , 1.f , 1.f , - 1.f );
2003-09-09 01:32:32 +00:00
/* XXX: Hack: we need to scale the reverse shift by the zoom. */
float fMiniPercent = GAMESTATE -> m_CurrentPlayerOptions [ pn ]. m_fEffects [ PlayerOptions :: EFFECT_MINI ];
float fZoom = 1 - fMiniPercent * 0.5f ;
f += SCALE ( GAMESTATE -> m_CurrentPlayerOptions [ pn ]. GetReversePercentForColumn ( iCol ), 0.f , 1.f , 0.f , fYReverseOffsetPixels / fZoom );
2003-08-16 23:34:47 +00:00
const float * fEffects = GAMESTATE -> m_CurrentPlayerOptions [ pn ]. m_fEffects ;
if ( fEffects [ PlayerOptions :: EFFECT_TIPSY ] > 0 )
f += fEffects [ PlayerOptions :: EFFECT_TIPSY ] * ( cosf ( RageTimer :: GetTimeSinceStart () * 1.2f + iCol * 2.f ) * ARROW_SIZE * 0.4f );
return f ;
2002-02-24 10:31:20 +00:00
}
2002-08-01 03:15:27 +00:00
2002-08-29 01:38:21 +00:00
const float fCenterLine = 160 ; // from fYPos == 0
const float fFadeDist = 100 ;
// used by ArrowGetAlpha and ArrowGetGlow below
2003-09-04 05:27:43 +00:00
static float ArrowGetPercentVisible ( PlayerNumber pn , int iCol , float fYPos , float fYReverseOffsetPixels )
2002-08-29 01:38:21 +00:00
{
2003-09-09 01:32:32 +00:00
/* Ack. What we're really doing here is unapplying reverse--what we really want is the Y position
* *with* EFFECT_TIPSY, but without reverse; this is tricky since EFFECT_TIPSY is applied after
* reverse. This would be more straightforward if we were passed fYPosWORev; we could just apply
* EFFECT_TIPSY. That would make the interface more complicated, however. */
const float fMiniPercent = GAMESTATE -> m_CurrentPlayerOptions [ pn ]. m_fEffects [ PlayerOptions :: EFFECT_MINI ];
const float fZoom = 1 - fMiniPercent * 0.5f ;
2003-08-17 00:15:54 +00:00
if ( GAMESTATE -> m_CurrentPlayerOptions [ pn ]. GetReversePercentForColumn ( iCol ) > 0.5f )
2003-09-04 05:27:43 +00:00
{
2003-09-09 01:32:32 +00:00
fYPos -= SCALE ( GAMESTATE -> m_CurrentPlayerOptions [ pn ]. GetReversePercentForColumn ( iCol ), 0.f , 1.f , 0.f , fYReverseOffsetPixels / fZoom );
2003-09-04 05:27:43 +00:00
fYPos /= SCALE ( GAMESTATE -> m_CurrentPlayerOptions [ pn ]. GetReversePercentForColumn ( iCol ), 0.f , 1.f , 1.f , - 1.f );
2003-09-09 01:32:32 +00:00
2003-09-04 05:27:43 +00:00
}
2002-08-29 01:38:21 +00:00
2003-09-09 01:32:32 +00:00
/* Another mini hack: if EFFECT_MINI is on, then our fYPos range is eg. 0..640, when we really
* want 0..320: */
fYPos *= fZoom ;
2003-04-17 21:44:33 +00:00
const float fDistFromCenterLine = fYPos - fCenterLine ;
if ( fYPos < 0 ) // past Gray Arrows
2003-02-26 23:26:57 +00:00
return 1 ; // totally visible
2002-08-29 01:38:21 +00:00
2002-02-24 10:31:20 +00:00
2003-02-26 23:26:57 +00:00
const float * fAppearances = GAMESTATE -> m_CurrentPlayerOptions [ pn ]. m_fAppearances ;
float fVisibleAdjust = 0 ;
if ( fAppearances [ PlayerOptions :: APPEARANCE_HIDDEN ] > 0 )
fVisibleAdjust += fAppearances [ PlayerOptions :: APPEARANCE_HIDDEN ] * SCALE ( fDistFromCenterLine , 0 , fFadeDist , - 1 , 0 );
if ( fAppearances [ PlayerOptions :: APPEARANCE_SUDDEN ] > 0 )
fVisibleAdjust += fAppearances [ PlayerOptions :: APPEARANCE_SUDDEN ] * SCALE ( fDistFromCenterLine , 0 , - fFadeDist , - 1 , 0 );
if ( fAppearances [ PlayerOptions :: APPEARANCE_STEALTH ] > 0 )
fVisibleAdjust += fAppearances [ PlayerOptions :: APPEARANCE_STEALTH ] * - 1 ;
if ( fAppearances [ PlayerOptions :: APPEARANCE_BLINK ] > 0 )
2003-04-21 00:12:42 +00:00
{
float f = sinf ( RageTimer :: GetTimeSinceStart () * 10 );
f = froundf ( f , 0.3333f );
fVisibleAdjust += SCALE ( f , 0 , 1 , - 1 , 0 );
}
2003-05-04 13:58:45 +00:00
if ( fAppearances [ PlayerOptions :: APPEARANCE_RANDOMVANISH ] > 0 )
{
float adjustment = GAMESTATE -> m_CurrentPlayerOptions [ pn ]. m_fScrollSpeed ;
if ( adjustment == 0 )
adjustment = 1 ;
float fRealCenterLine = fCenterLine / adjustment ;
const float fDistFromRealCenterLine = fYPos - fRealCenterLine ;
float fRealFadeDist = ( fFadeDist - 20 ) / adjustment ;
if ( fYPos >= fRealCenterLine + ( fRealFadeDist ))
{
fVisibleAdjust += fAppearances [ PlayerOptions :: APPEARANCE_RANDOMVANISH ] * ( SCALE ( fDistFromRealCenterLine - fRealFadeDist , 0 , ( fRealFadeDist ), - 1 , 0 )); // go hidden
}
else if ( fYPos <= fRealCenterLine - ( fRealFadeDist ))
{
fVisibleAdjust += fAppearances [ PlayerOptions :: APPEARANCE_RANDOMVANISH ] * ( SCALE ( fDistFromRealCenterLine + fRealFadeDist , 0 , - (( fRealFadeDist )), - 1 , 0 )); // suddenly appear
}
else
{
fVisibleAdjust += fAppearances [ PlayerOptions :: APPEARANCE_RANDOMVANISH ] * - 1 ; // be invisible
}
}
2003-02-26 23:26:57 +00:00
return clamp ( 1 + fVisibleAdjust , 0 , 1 );
2002-08-29 01:38:21 +00:00
}
2002-02-24 10:31:20 +00:00
2003-09-04 05:27:43 +00:00
float ArrowGetAlpha ( PlayerNumber pn , int iCol , float fYPos , float fPercentFadeToFail , float fYReverseOffsetPixels )
2002-08-29 01:38:21 +00:00
{
2003-05-29 00:15:51 +00:00
// fYPos /= GAMESTATE->m_CurrentPlayerOptions[pn].m_fScrollSpeed;
2003-09-04 05:27:43 +00:00
float fPercentVisible = ArrowGetPercentVisible ( pn , iCol , fYPos , fYReverseOffsetPixels );
2002-09-05 03:45:07 +00:00
if ( fPercentFadeToFail != - 1 )
fPercentVisible = 1 - fPercentFadeToFail ;
return ( fPercentVisible > 0.5f ) ? 1.0f : 0.0f ;
2002-08-29 01:38:21 +00:00
}
2002-02-24 10:31:20 +00:00
2003-09-04 05:27:43 +00:00
float ArrowGetGlow ( PlayerNumber pn , int iCol , float fYPos , float fPercentFadeToFail , float fYReverseOffsetPixels )
2002-08-29 01:38:21 +00:00
{
2003-05-29 00:15:51 +00:00
// fYPos /= GAMESTATE->m_CurrentPlayerOptions[pn].m_fScrollSpeed;
2003-09-04 05:27:43 +00:00
float fPercentVisible = ArrowGetPercentVisible ( pn , iCol , fYPos , fYReverseOffsetPixels );
2002-09-05 03:45:07 +00:00
if ( fPercentFadeToFail != - 1 )
fPercentVisible = 1 - fPercentFadeToFail ;
const float fDistFromHalf = fabsf ( fPercentVisible - 0.5f );
2002-09-02 21:59:58 +00:00
return SCALE ( fDistFromHalf , 0 , 0.5f , 1.3f , 0 );
2002-08-29 01:38:21 +00:00
}
2003-02-12 22:05:14 +00:00
2003-02-17 02:45:30 +00:00
float ArrowGetBrightness ( PlayerNumber pn , float fNoteBeat )
2003-02-12 22:05:14 +00:00
{
2003-02-18 23:15:38 +00:00
if ( GAMESTATE -> m_bEditing )
return 1 ;
2003-02-17 02:45:30 +00:00
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 ArrowGetZPos ( PlayerNumber pn , int iCol , float fYPos )
{
2003-07-09 01:34:48 +00:00
float fZPos = 0 ;
const float * fEffects = GAMESTATE -> m_CurrentPlayerOptions [ pn ]. m_fEffects ;
if ( fEffects [ PlayerOptions :: EFFECT_BUMPY ] > 0 )
fZPos += fEffects [ PlayerOptions :: EFFECT_BUMPY ] * 40 * sinf ( fYPos / 16.0f );
return fZPos ;
}
bool ArrowsNeedZBuffer ( PlayerNumber pn )
{
const float * fEffects = GAMESTATE -> m_CurrentPlayerOptions [ pn ]. m_fEffects ;
if ( fEffects [ PlayerOptions :: EFFECT_BUMPY ] > 0 )
return true ;
return false ;
2003-07-09 00:49:05 +00:00
}
2003-09-04 05:27:43 +00:00