Added interface for controlling the behavior of the hasts system. Added support for negative haste. Moves haste rate calculations to UpdateHasteRate. GetHasteRate now just returns the calculated value. Added FLOAT_NO_SPEED_INTERFACE and FLOAT_TABLE_INTERFACE macros to OptionsBinding.h
This commit is contained in:
@@ -1284,6 +1284,11 @@
|
|||||||
<Function name='GetLifeMeter'/>
|
<Function name='GetLifeMeter'/>
|
||||||
<Function name='GetNextCourseSong'/>
|
<Function name='GetNextCourseSong'/>
|
||||||
<Function name='GetPlayerInfo'/>
|
<Function name='GetPlayerInfo'/>
|
||||||
|
<Function name='GetTrueBPS'/>
|
||||||
|
<Function name='HasteAddAmounts'/>
|
||||||
|
<Function name='HasteLifeSwitchPoint'/>
|
||||||
|
<Function name='HasteTimeBetweenUpdates'/>
|
||||||
|
<Function name='HasteTurningPoints'/>
|
||||||
<Function name='IsPaused'/>
|
<Function name='IsPaused'/>
|
||||||
<Function name='PauseGame'/>
|
<Function name='PauseGame'/>
|
||||||
</Class>
|
</Class>
|
||||||
|
|||||||
@@ -3598,6 +3598,27 @@ save yourself some time, copy this for undocumented things:
|
|||||||
<Function name='GetPlayerInfo' return='PlayerInfo' arguments='PlayerNumber pn'>
|
<Function name='GetPlayerInfo' return='PlayerInfo' arguments='PlayerNumber pn'>
|
||||||
Returns the PlayerInfo for player <code>pn</code>.
|
Returns the PlayerInfo for player <code>pn</code>.
|
||||||
</Function>
|
</Function>
|
||||||
|
<Function name='GetTrueBPS' return='float' arguments='PlayerNumber pn'>
|
||||||
|
Returns the current true beats per second for the specified player.<br />
|
||||||
|
This takes into account the current music rate and the current haste effect.<br />
|
||||||
|
If you are displaying the BPM on ScreenGameplay, this is what you should use to have correct behavior when Haste and/or a music rate mod are in effect.
|
||||||
|
</Function>
|
||||||
|
<Function name='HasteAddAmounts' return='{float}' arguments='{float}'>
|
||||||
|
This is part of the system for controlling how haste behaves. <br />
|
||||||
|
Read Docs/Themerdocs/haste.txt.
|
||||||
|
</Function>
|
||||||
|
<Function name='HasteLifeSwitchPoint' return='float' arguments='float'>
|
||||||
|
This is part of the system for controlling how haste behaves. <br />
|
||||||
|
Read Docs/Themerdocs/haste.txt.
|
||||||
|
</Function>
|
||||||
|
<Function name='HasteTimeBetweenUpdates' return='float' arguments='float'>
|
||||||
|
This is part of the system for controlling how haste behaves. <br />
|
||||||
|
Read Docs/Themerdocs/haste.txt.
|
||||||
|
</Function>
|
||||||
|
<Function name='HasteTurningPoints' return='{float}' arguments='{float}'>
|
||||||
|
This is part of the system for controlling how haste behaves. <br />
|
||||||
|
Read Docs/Themerdocs/haste.txt.
|
||||||
|
</Function>
|
||||||
<Function name='SetNewScreen' return='void' arguments='string s'>
|
<Function name='SetNewScreen' return='void' arguments='string s'>
|
||||||
Sets the next Screen to be loaded.
|
Sets the next Screen to be loaded.
|
||||||
</Function>
|
</Function>
|
||||||
@@ -4092,6 +4113,7 @@ save yourself some time, copy this for undocumented things:
|
|||||||
Limited to the range 0 < rate <= 3 because speeds greater than 3 are likely to crash.
|
Limited to the range 0 < rate <= 3 because speeds greater than 3 are likely to crash.
|
||||||
</Function>
|
</Function>
|
||||||
<Function name='Haste' return='float' arguments='float h'>
|
<Function name='Haste' return='float' arguments='float h'>
|
||||||
|
Not actually usable as a float. Any value other than 0 is considered "on".
|
||||||
</Function>
|
</Function>
|
||||||
</Class>
|
</Class>
|
||||||
<Class name='SongPosition'>
|
<Class name='SongPosition'>
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
Traditionally, the Haste effect is an effect where the song speeds up when the player is doing well, and slows down when the player is doing poorly.
|
||||||
|
This document lists the lua functions that change the behavior of Haste and some suggested practices.
|
||||||
|
|
||||||
|
All of these functions are combined Get/Set. This means that they always return the value as it was before the function was called, and the parameters are optional. "prev_value= SongOptions:Haste(new_value)" (somewhere else) "SongOptions:Haste(prev_value)" is an example of using this to set a new value, store the previous, then later restore the previous value.
|
||||||
|
|
||||||
|
SongOptions:Haste(n)
|
||||||
|
Gets/Sets the haste multiplier. The haste multiplier is applied to the Haste effect as a scale factor. Negative haste works as the inverse of normal haste.
|
||||||
|
SongOptions:Haste(0) disables Haste.
|
||||||
|
Limited to the range of -1 to 1, but is a floating point value.
|
||||||
|
|
||||||
|
ScreenGameplay:HasteTurningPoints({a, b ...})
|
||||||
|
Gets/Sets the turning points at which the haste effect changes.
|
||||||
|
There must be at least two turning points.
|
||||||
|
Each turning point must be greater than the previous.
|
||||||
|
Each turning point must be between -1 and 1.
|
||||||
|
|
||||||
|
ScreenGameplay:HasteAddAmounts({a, b ...})
|
||||||
|
Gets/Sets the amounts that are added to the song speed at each turning point.
|
||||||
|
There must be at least two add amounts.
|
||||||
|
Each add amount must be greater than the previous.
|
||||||
|
Each add amount must be between -1 and 1.
|
||||||
|
If you allow negative haste in your theme, do not allow it to be combined with an add amount of 1. It won't crash, but it will bring the song to a standstill. The same goes for positive haste and add amount -1.
|
||||||
|
|
||||||
|
ScreenGameplay:HasteTimeBetweenUpdates(n)
|
||||||
|
Gets/Sets the amount of time between Haste updates. Every n seconds, if any player has hit all the steps since the last update, the value used to determine where the player is on the haste scale increases by .1.
|
||||||
|
|
||||||
|
ScreenGameplay:HasteLifeSwitchPoint(n)
|
||||||
|
Gets/Sets the point below which the haste effect depends on the life bar.
|
||||||
|
|
||||||
|
ScreenGameplay:GetTrueBPS(player_number)
|
||||||
|
Returns the current true beats per second for the specified player.
|
||||||
|
This takes into account the current music rate and the current haste effect.
|
||||||
|
If you are displaying the BPM on ScreenGameplay, this is what you should use to have correct behavior when Haste and/or a music rate mod are in effect.
|
||||||
|
|
||||||
|
|
||||||
|
Full explanation:
|
||||||
|
Variables: (not the names used in the source code)
|
||||||
|
haste_score:
|
||||||
|
Controls where the player is on the scale from minimum haste to maximum haste.
|
||||||
|
Ranges from -1 to 1.
|
||||||
|
Mode 1: Player's life is above haste_life_switch_point.
|
||||||
|
haste_score starts at 0 and increases by .1 every haste_update_time seconds if the player has hit all steps.
|
||||||
|
Mode 2: Player's life is at or below haste_life_switch_point.
|
||||||
|
haste_score is between -1 and 0, scaled by the player's life. At 0 life, haste_score is -1. At haste_life_switch_point, haste_score is at 0.
|
||||||
|
haste_life_switch_point:
|
||||||
|
The point at which haste_score switches from Mode 1 to Mode 2.
|
||||||
|
turning_points:
|
||||||
|
add_amounts:
|
||||||
|
There must be the same number of turning_points as add_amounts.
|
||||||
|
There must be at least two turning_points/add_amounts.
|
||||||
|
If either of these conditions is false, haste is disabled.
|
||||||
|
Values must be between -1 and 1. Attempting to set an invalid value will throw an error.
|
||||||
|
haste_score is a single linear input. turning_points and add_amounts are used to transform this single linear input into a set of connected lines.
|
||||||
|
The turning_points adjacent to haste_score's value are used as the "from" range for scaling haste_score to speed_add. This shall be referred to as from_low and from_high.
|
||||||
|
The add_amounts that match up to the turning_points are used as the "to" range for scaling haste_score to speed_add. This shall be referred to as to_low and to_high.
|
||||||
|
So when haste_score is equal to from_low, speed_add comes out as to_low. Wheen haste_score is equal to from_high, speed_add comes out as to_high.
|
||||||
|
speed_add:
|
||||||
|
The amount that is added to 1 to get the final haste effect.
|
||||||
|
After being calculated from turning_points and add_amounts, speed_add is multiplied by song_haste from the song options. This means that if song_haste is negative, speed_add will work in reverse, slowing the song down.
|
||||||
|
accumulated_seconds:
|
||||||
|
While the song is sped up, the player accumulates seconds. While the song is slowed down, the player loses seconds. When the player has 0 seconds, the song is no longer slowed down. This prevents a player from keeping the song perpetually slow by keeping their life bar low.
|
||||||
|
If song_haste is negative, this works in reverse.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
-- This is what the default haste settings would be if they were set through the above functions.
|
||||||
|
ScreenGameplay:HasteTurningPoints({-1, 0, .3, 1})
|
||||||
|
ScreenGameplay:HasteAddAmounts({-.5, 0, .2, .5})
|
||||||
|
ScreenGameplay:HasteTimeBetweenUpdates(4)
|
||||||
|
ScreenGameplay:HasteLifeSwitchPoint(.5)
|
||||||
|
-- haste_score goes up by .1 every 4 seconds if the player hits all steps.
|
||||||
|
-- When haste_score is between -1 and 0 (player's life is between 0 and .5), speed_add will be between -.5 and 0 before being multiplied by song_haste.
|
||||||
|
-- When haste_score is between 0 and .3 (player life above .5), speed_add will be between 0 and .2 before being multiplied by song_haste.
|
||||||
|
-- When haste_score is between .3 and 1 (player life above .5), speed_add will be between .2 and .5 before being multiplied by song_haste.
|
||||||
|
|
||||||
|
|
||||||
|
Source code references to be used by people looking to improve this explanation:
|
||||||
|
ScreenGameplay::UpdateHasteRate
|
||||||
|
ScreenGameplay.cpp:1743-1757 (where UpdateHasteRate is called and AccumulatedHasteSeconds is updated)
|
||||||
|
ScreenGameplay::Init (lines 355-369)
|
||||||
@@ -33,6 +33,22 @@
|
|||||||
} \
|
} \
|
||||||
return 2; \
|
return 2; \
|
||||||
}
|
}
|
||||||
|
#define FLOAT_NO_SPEED_INTERFACE(func_name, member, valid) \
|
||||||
|
static int func_name(T* p, lua_State* L) \
|
||||||
|
{ \
|
||||||
|
DefaultNilArgs(L, 1); \
|
||||||
|
lua_pushnumber(L, p->m_f ## member); \
|
||||||
|
if(lua_isnumber(L, 1)) \
|
||||||
|
{ \
|
||||||
|
float v= FArg(1); \
|
||||||
|
if(!valid) \
|
||||||
|
{ \
|
||||||
|
luaL_error(L, "Invalid value %f", v); \
|
||||||
|
} \
|
||||||
|
p->m_f ## member = v; \
|
||||||
|
} \
|
||||||
|
return 1; \
|
||||||
|
}
|
||||||
#define INT_INTERFACE(func_name, member) \
|
#define INT_INTERFACE(func_name, member) \
|
||||||
static int func_name(T* p, lua_State* L) \
|
static int func_name(T* p, lua_State* L) \
|
||||||
{ \
|
{ \
|
||||||
@@ -66,6 +82,36 @@
|
|||||||
} \
|
} \
|
||||||
return 1; \
|
return 1; \
|
||||||
}
|
}
|
||||||
|
// Walk the table to make sure all entries are valid before setting.
|
||||||
|
#define FLOAT_TABLE_INTERFACE(func_name, member, valid) \
|
||||||
|
static int func_name(T* p, lua_State* L) \
|
||||||
|
{ \
|
||||||
|
DefaultNilArgs(L, 1); \
|
||||||
|
lua_createtable(L, p->m_ ## member.size(), 0); \
|
||||||
|
for(size_t n= 0; n < p->m_ ## member.size(); ++n) \
|
||||||
|
{ \
|
||||||
|
lua_pushnumber(L, p->m_ ## member[n]); \
|
||||||
|
lua_rawseti(L, -2, n+1); \
|
||||||
|
} \
|
||||||
|
if(lua_istable(L, 1)) \
|
||||||
|
{ \
|
||||||
|
size_t size= lua_objlen(L, 1); \
|
||||||
|
if(valid(L, 1)) \
|
||||||
|
{ \
|
||||||
|
p->m_ ## member.clear(); \
|
||||||
|
p->m_ ## member.reserve(size); \
|
||||||
|
for(size_t n= 1; n <= size; ++n) \
|
||||||
|
{ \
|
||||||
|
lua_pushnumber(L, n); \
|
||||||
|
lua_gettable(L, 1); \
|
||||||
|
float v= FArg(-1); \
|
||||||
|
p->m_ ## member.push_back(v); \
|
||||||
|
lua_pop(L, 1); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
return 1; \
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
+134
-15
@@ -352,6 +352,21 @@ void ScreenGameplay::Init()
|
|||||||
UNPAUSE_WITH_START.Load( m_sName, "UnpauseWithStart");
|
UNPAUSE_WITH_START.Load( m_sName, "UnpauseWithStart");
|
||||||
SURVIVAL_MOD_OVERRIDE.Load(m_sName, "SurvivalModOverride");
|
SURVIVAL_MOD_OVERRIDE.Load(m_sName, "SurvivalModOverride");
|
||||||
|
|
||||||
|
// Default values. The theme can set its own through the Lua interface.
|
||||||
|
m_HasteTurningPoints.clear();
|
||||||
|
m_HasteTurningPoints.push_back(-1);
|
||||||
|
m_HasteTurningPoints.push_back(0);
|
||||||
|
m_HasteTurningPoints.push_back(.3);
|
||||||
|
m_HasteTurningPoints.push_back(1);
|
||||||
|
m_HasteAddAmounts.clear();
|
||||||
|
m_HasteAddAmounts.push_back(-.5);
|
||||||
|
m_HasteAddAmounts.push_back(0);
|
||||||
|
m_HasteAddAmounts.push_back(.2);
|
||||||
|
m_HasteAddAmounts.push_back(.5);
|
||||||
|
m_fHasteTimeBetweenUpdates= 4;
|
||||||
|
m_fHasteLifeSwitchPoint= .5;
|
||||||
|
m_fCurrHasteRate= 1; // Should this be in BeginSong? Not sure whether it should carry over between songs.
|
||||||
|
|
||||||
if( UseSongBackgroundAndForeground() )
|
if( UseSongBackgroundAndForeground() )
|
||||||
{
|
{
|
||||||
m_pSongBackground = new Background;
|
m_pSongBackground = new Background;
|
||||||
@@ -1616,7 +1631,7 @@ void ScreenGameplay::Update( float fDeltaTime )
|
|||||||
fSpeed *= GetHasteRate();
|
fSpeed *= GetHasteRate();
|
||||||
|
|
||||||
RageSoundParams p = m_pSoundMusic->GetParams();
|
RageSoundParams p = m_pSoundMusic->GetParams();
|
||||||
if( fabsf(p.m_fSpeed - fSpeed) > 0.01f )
|
if( fabsf(p.m_fSpeed - fSpeed) > 0.01f && fSpeed >= 0.0f)
|
||||||
{
|
{
|
||||||
p.m_fSpeed = fSpeed;
|
p.m_fSpeed = fSpeed;
|
||||||
m_pSoundMusic->SetParams( p );
|
m_pSoundMusic->SetParams( p );
|
||||||
@@ -1725,12 +1740,23 @@ void ScreenGameplay::Update( float fDeltaTime )
|
|||||||
{
|
{
|
||||||
STATSMAN->m_CurStageStats.m_fStepsSeconds += fUnscaledDeltaTime;
|
STATSMAN->m_CurStageStats.m_fStepsSeconds += fUnscaledDeltaTime;
|
||||||
|
|
||||||
|
UpdateHasteRate();
|
||||||
|
|
||||||
if( GAMESTATE->m_SongOptions.GetCurrent().m_fHaste != 0.0f )
|
if( GAMESTATE->m_SongOptions.GetCurrent().m_fHaste != 0.0f )
|
||||||
{
|
{
|
||||||
float fHasteRate = GetHasteRate();
|
float fHasteRate = GetHasteRate();
|
||||||
|
// For negative haste, accumulate seconds while the song is slowed down.
|
||||||
|
if(GAMESTATE->m_SongOptions.GetCurrent().m_fHaste < 0)
|
||||||
|
{
|
||||||
|
GAMESTATE->m_fAccumulatedHasteSeconds -= (fUnscaledDeltaTime * fHasteRate) - fUnscaledDeltaTime;
|
||||||
|
}
|
||||||
|
// For positive haste, accumulate seconds while the song is sped up.
|
||||||
|
else
|
||||||
|
{
|
||||||
GAMESTATE->m_fAccumulatedHasteSeconds += (fUnscaledDeltaTime * fHasteRate) - fUnscaledDeltaTime;
|
GAMESTATE->m_fAccumulatedHasteSeconds += (fUnscaledDeltaTime * fHasteRate) - fUnscaledDeltaTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check for end of song
|
// Check for end of song
|
||||||
{
|
{
|
||||||
@@ -1894,9 +1920,14 @@ void ScreenGameplay::Update( float fDeltaTime )
|
|||||||
}
|
}
|
||||||
|
|
||||||
float ScreenGameplay::GetHasteRate()
|
float ScreenGameplay::GetHasteRate()
|
||||||
|
{
|
||||||
|
return m_fCurrHasteRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenGameplay::UpdateHasteRate()
|
||||||
{
|
{
|
||||||
if( GAMESTATE->m_Position.m_fMusicSeconds < GAMESTATE->m_fLastHasteUpdateMusicSeconds || // new song
|
if( GAMESTATE->m_Position.m_fMusicSeconds < GAMESTATE->m_fLastHasteUpdateMusicSeconds || // new song
|
||||||
GAMESTATE->m_Position.m_fMusicSeconds > GAMESTATE->m_fLastHasteUpdateMusicSeconds + 4 )
|
GAMESTATE->m_Position.m_fMusicSeconds > GAMESTATE->m_fLastHasteUpdateMusicSeconds + m_fHasteTimeBetweenUpdates )
|
||||||
{
|
{
|
||||||
bool bAnyPlayerHitAllNotes = false;
|
bool bAnyPlayerHitAllNotes = false;
|
||||||
FOREACH_EnabledPlayerInfo( m_vPlayerInfo, pi )
|
FOREACH_EnabledPlayerInfo( m_vPlayerInfo, pi )
|
||||||
@@ -1929,27 +1960,70 @@ float ScreenGameplay::GetHasteRate()
|
|||||||
continue;
|
continue;
|
||||||
fMaxLife = max( fMaxLife, pi->m_pLifeMeter->GetLife() );
|
fMaxLife = max( fMaxLife, pi->m_pLifeMeter->GetLife() );
|
||||||
}
|
}
|
||||||
if( fMaxLife < 0.5f )
|
if( fMaxLife <= m_fHasteLifeSwitchPoint )
|
||||||
GAMESTATE->m_fHasteRate = SCALE( fMaxLife, 0.0f, 0.5f, -1.0f, 0.0f );
|
GAMESTATE->m_fHasteRate = SCALE( fMaxLife, 0.0f, m_fHasteLifeSwitchPoint, -1.0f, 0.0f );
|
||||||
|
CLAMP( GAMESTATE->m_fHasteRate, -1.0f, +1.0f );
|
||||||
|
|
||||||
float fSpeed = 1.0f;
|
float fSpeed = 1.0f;
|
||||||
if( GAMESTATE->m_fHasteRate < 0 )
|
// If there are no turning points or no add amounts, the bad themer probably thinks that's a way to disable haste.
|
||||||
fSpeed = SCALE( GAMESTATE->m_fHasteRate, -1.0f, 0.0f, 0.5f, 1.0f );
|
// Since we're outside a lua function, crashing (asserting) won't point back to the source of the problem.
|
||||||
else if( GAMESTATE->m_fHasteRate < 0.3f )
|
if(m_HasteTurningPoints.size() < 2 || m_HasteAddAmounts.size() < 2 ||
|
||||||
fSpeed = SCALE( GAMESTATE->m_fHasteRate, 0.0f, 0.3f, 1.0f, 1.2f );
|
m_HasteTurningPoints.size() != m_HasteAddAmounts.size())
|
||||||
else
|
{
|
||||||
fSpeed = SCALE( GAMESTATE->m_fHasteRate, 0.3f, 1.0f, 1.2f, 1.5f );
|
m_fCurrHasteRate= fSpeed;
|
||||||
fSpeed *= GAMESTATE->m_SongOptions.GetCurrent().m_fHaste;
|
return;
|
||||||
|
}
|
||||||
|
float options_haste= GAMESTATE->m_SongOptions.GetCurrent().m_fHaste;
|
||||||
|
float scale_from_low= -1;
|
||||||
|
float scale_from_high= 1;
|
||||||
|
float scale_to_low= 0;
|
||||||
|
float scale_to_high=0;
|
||||||
|
for(size_t turning_point= 0; turning_point < m_HasteTurningPoints.size();
|
||||||
|
++turning_point)
|
||||||
|
{
|
||||||
|
float curr_turning_point= m_HasteTurningPoints[turning_point];
|
||||||
|
scale_from_high= curr_turning_point;
|
||||||
|
scale_to_high= m_HasteAddAmounts[turning_point];
|
||||||
|
if(GAMESTATE->m_fHasteRate < curr_turning_point)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
scale_from_low= curr_turning_point;
|
||||||
|
scale_to_low= m_HasteAddAmounts[turning_point];
|
||||||
|
}
|
||||||
|
// If negative haste is being used, the game instead slows down when the player does well.
|
||||||
|
float speed_add= SCALE(GAMESTATE->m_fHasteRate, scale_from_low, scale_from_high, scale_to_low, scale_to_high) * options_haste;
|
||||||
|
if(scale_from_low == scale_from_high)
|
||||||
|
{
|
||||||
|
speed_add= scale_to_high * options_haste;
|
||||||
|
}
|
||||||
|
CLAMP(speed_add, -1.0f, 1.0f);
|
||||||
|
|
||||||
if( GAMESTATE->m_fAccumulatedHasteSeconds <= 1 )
|
// Only adjust speed_add by AccumulatedHasteSeconds when the player is losing seconds. Otherwise, gaining the first second is interfered with.
|
||||||
|
bool losing_seconds= false;
|
||||||
|
if(options_haste > 0)
|
||||||
|
{
|
||||||
|
losing_seconds= speed_add < 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
losing_seconds= speed_add > 0;
|
||||||
|
}
|
||||||
|
if( losing_seconds && GAMESTATE->m_fAccumulatedHasteSeconds <= 1 )
|
||||||
{
|
{
|
||||||
/* Only allow slowing down the song while the players have accumulated
|
/* Only allow slowing down the song while the players have accumulated
|
||||||
* haste. This prevents dragging on the song by keeping the life meter
|
* haste. This prevents dragging on the song by keeping the life meter
|
||||||
* nearly empty. */
|
* nearly empty. */
|
||||||
float fClamped = max( 1.0f, fSpeed );
|
/* In positive haste mode, the player accumulates seconds while the song
|
||||||
fSpeed = lerp( GAMESTATE->m_fAccumulatedHasteSeconds, fClamped, fSpeed );
|
* is sped up, and loses them while the song is slowed down. "<= 1"
|
||||||
|
* means that the player is only eligible to slow the song down when
|
||||||
|
* they are down to their last accumulated second. -Kyz */
|
||||||
|
// 1 second left is full speed_add, 0 seconds left is no speed_add.
|
||||||
|
float clamp_secs= max(0, GAMESTATE->m_fAccumulatedHasteSeconds);
|
||||||
|
speed_add = speed_add * clamp_secs;
|
||||||
}
|
}
|
||||||
return fSpeed;
|
fSpeed += speed_add;
|
||||||
|
m_fCurrHasteRate= fSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenGameplay::UpdateLights()
|
void ScreenGameplay::UpdateLights()
|
||||||
@@ -2823,6 +2897,7 @@ bool ScreenGameplay::LoadReplay()
|
|||||||
|
|
||||||
// lua start
|
// lua start
|
||||||
#include "LuaBinding.h"
|
#include "LuaBinding.h"
|
||||||
|
#include "OptionsBinding.h"
|
||||||
|
|
||||||
/** @brief Allow Lua to have access to the ScreenGameplay. */
|
/** @brief Allow Lua to have access to the ScreenGameplay. */
|
||||||
class LunaScreenGameplay: public Luna<ScreenGameplay>
|
class LunaScreenGameplay: public Luna<ScreenGameplay>
|
||||||
@@ -2867,6 +2942,45 @@ public:
|
|||||||
static int PauseGame( T* p, lua_State *L ) { p->Pause( BArg(1)); return 0; }
|
static int PauseGame( T* p, lua_State *L ) { p->Pause( BArg(1)); return 0; }
|
||||||
static int IsPaused( T* p, lua_State *L ) { lua_pushboolean( L, p->IsPaused() ); return 1; }
|
static int IsPaused( T* p, lua_State *L ) { lua_pushboolean( L, p->IsPaused() ); return 1; }
|
||||||
static int GetHasteRate( T* p, lua_State *L ) { lua_pushnumber( L, p->GetHasteRate() ); return 1; }
|
static int GetHasteRate( T* p, lua_State *L ) { lua_pushnumber( L, p->GetHasteRate() ); return 1; }
|
||||||
|
static bool TurningPointsValid(lua_State* L, int index)
|
||||||
|
{
|
||||||
|
size_t size= lua_objlen(L, index);
|
||||||
|
if(size < 2)
|
||||||
|
{
|
||||||
|
luaL_error(L, "Invalid number of entries %zu", size);
|
||||||
|
}
|
||||||
|
float prev_turning= -1;
|
||||||
|
for(size_t n= 1; n < size; ++n)
|
||||||
|
{
|
||||||
|
lua_pushnumber(L, n);
|
||||||
|
lua_gettable(L, index);
|
||||||
|
float v= FArg(-1);
|
||||||
|
if(v < prev_turning || v > 1)
|
||||||
|
{
|
||||||
|
luaL_error(L, "Invalid value %f", v);
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
static bool AddAmountsValid(lua_State* L, int index)
|
||||||
|
{
|
||||||
|
return TurningPointsValid(L, index);
|
||||||
|
}
|
||||||
|
FLOAT_TABLE_INTERFACE(HasteTurningPoints, HasteTurningPoints, TurningPointsValid);
|
||||||
|
FLOAT_TABLE_INTERFACE(HasteAddAmounts, HasteAddAmounts, AddAmountsValid);
|
||||||
|
FLOAT_NO_SPEED_INTERFACE(HasteTimeBetweenUpdates, HasteTimeBetweenUpdates, (v > 0));
|
||||||
|
FLOAT_NO_SPEED_INTERFACE(HasteLifeSwitchPoint, HasteLifeSwitchPoint, (v >= 0 && v <= 1));
|
||||||
|
static int GetTrueBPS(T* p, lua_State* L)
|
||||||
|
{
|
||||||
|
PlayerNumber pn= Enum::Check<PlayerNumber>(L, 1);
|
||||||
|
float haste= p->GetHasteRate();
|
||||||
|
float rate= GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate;
|
||||||
|
float bps= GAMESTATE->m_pPlayerState[pn]->m_Position.m_fCurBPS;
|
||||||
|
float true_bps= haste * rate * bps;
|
||||||
|
lua_pushnumber(L, true_bps);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
LunaScreenGameplay()
|
LunaScreenGameplay()
|
||||||
{
|
{
|
||||||
@@ -2879,6 +2993,11 @@ public:
|
|||||||
ADD_METHOD( PauseGame );
|
ADD_METHOD( PauseGame );
|
||||||
ADD_METHOD( IsPaused );
|
ADD_METHOD( IsPaused );
|
||||||
ADD_METHOD( GetHasteRate );
|
ADD_METHOD( GetHasteRate );
|
||||||
|
ADD_METHOD( HasteTurningPoints );
|
||||||
|
ADD_METHOD( HasteAddAmounts );
|
||||||
|
ADD_METHOD( HasteTimeBetweenUpdates );
|
||||||
|
ADD_METHOD( HasteLifeSwitchPoint );
|
||||||
|
ADD_METHOD( GetTrueBPS );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -172,6 +172,11 @@ public:
|
|||||||
bool IsPaused() const { return m_bPaused; }
|
bool IsPaused() const { return m_bPaused; }
|
||||||
float GetHasteRate();
|
float GetHasteRate();
|
||||||
|
|
||||||
|
vector<float> m_HasteTurningPoints; // Values at which the meaning of GAMESTATE->m_fHasteRate changes.
|
||||||
|
vector<float> m_HasteAddAmounts; // Amounts that are added to speed depending on what turning point has been passed.
|
||||||
|
float m_fHasteTimeBetweenUpdates; // Seconds between haste updates.
|
||||||
|
float m_fHasteLifeSwitchPoint; // Life amount below which GAMESTATE->m_fHasteRate is based on the life amount.
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void UpdateStageStats( MultiPlayer /* mp */ ) {}; // overridden for multiplayer
|
virtual void UpdateStageStats( MultiPlayer /* mp */ ) {}; // overridden for multiplayer
|
||||||
|
|
||||||
@@ -227,6 +232,10 @@ protected:
|
|||||||
|
|
||||||
virtual void InitSongQueues();
|
virtual void InitSongQueues();
|
||||||
|
|
||||||
|
void UpdateHasteRate();
|
||||||
|
float m_fCurrHasteRate;
|
||||||
|
// These exist so that the haste rate isn't recalculated every time GetHasteRate is called, which is at least once per frame. -Kyz
|
||||||
|
|
||||||
/** @brief The different game states of ScreenGameplay. */
|
/** @brief The different game states of ScreenGameplay. */
|
||||||
enum DancingState {
|
enum DancingState {
|
||||||
STATE_INTRO = 0, /**< The starting state, pressing Back isn't allowed here. */
|
STATE_INTRO = 0, /**< The starting state, pressing Back isn't allowed here. */
|
||||||
|
|||||||
+1
-1
@@ -296,7 +296,7 @@ public:
|
|||||||
BOOL_INTERFACE(SaveScore, SaveScore);
|
BOOL_INTERFACE(SaveScore, SaveScore);
|
||||||
BOOL_INTERFACE(SaveReplay, SaveReplay);
|
BOOL_INTERFACE(SaveReplay, SaveReplay);
|
||||||
FLOAT_INTERFACE(MusicRate, MusicRate, (v > 0.0f && v <= 3.0f)); // Greater than 3 seems to crash frequently, haven't investigated why. -Kyz
|
FLOAT_INTERFACE(MusicRate, MusicRate, (v > 0.0f && v <= 3.0f)); // Greater than 3 seems to crash frequently, haven't investigated why. -Kyz
|
||||||
FLOAT_INTERFACE(Haste, Haste, true);
|
FLOAT_INTERFACE(Haste, Haste, (v >= -1.0f && v <= 1.0f));
|
||||||
|
|
||||||
LunaSongOptions()
|
LunaSongOptions()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user