Esempio n. 1
0
void Difficulty::ProcessVSpeeds(TimingData& BPS, TimingData& VerticalSpeeds, double SpeedConstant)
{
    VerticalSpeeds.clear();

    if (SpeedConstant) // We're using a CMod, so further processing is pointless
    {
        TimingSegment VSpeed;
        VSpeed.Time = 0;
        VSpeed.Value = SpeedConstant;
        VerticalSpeeds.push_back(VSpeed);
        return;
    }

    // Calculate velocity at time based on BPM at time
    for (auto Time = BPS.begin();
    Time != BPS.end();
        ++Time)
    {
        float VerticalSpeed;
        TimingSegment VSpeed;

        if (Time->Value)
        {
            float spb = 1 / Time->Value;
            VerticalSpeed = MeasureBaseSpacing / (spb * 4);
        }
        else
            VerticalSpeed = 0;

        VSpeed.Value = VerticalSpeed;
        VSpeed.Time = Time->Time; // We blindly take the BPS time that had offset and drift applied.

        VerticalSpeeds.push_back(VSpeed);
    }

    // Let first speed be not-null.
    if (VerticalSpeeds.size() && VerticalSpeeds[0].Value == 0)
    {
        for (auto i = VerticalSpeeds.begin();
        i != VerticalSpeeds.end();
            ++i)
        {
            if (i->Value != 0)
                VerticalSpeeds[0].Value = i->Value;
        }
    }
}
Esempio n. 2
0
void Difficulty::ProcessSpeedVariations(TimingData& BPS, TimingData& VerticalSpeeds, double Drift)
{
    assert(Data != NULL);

    TimingData tVSpeeds = VerticalSpeeds; // We need this to store what values to change
    TimingData &Scrolls = Data->Scrolls;

    std::sort(Scrolls.begin(), Scrolls.end());

    for (TimingData::const_iterator Change = Scrolls.begin();
    Change != Scrolls.end();
        ++Change)
    {
        TimingData::const_iterator NextChange = (Change + 1);
        double ChangeTime = Change->Time + Drift + Offset;

        /*
            Find all VSpeeds
            if there exists a speed change which is virtually happening at the same time as this VSpeed
            modify it to be this value * factor
        */

        bool MoveOn = false;
        for (auto Time = VerticalSpeeds.begin();
        Time != VerticalSpeeds.end();
            ++Time)
        {
            if (abs(ChangeTime - Time->Time) < 0.00001)
            {
                Time->Value *= Change->Value;
                MoveOn = true;
            }
        }

        if (MoveOn) continue;

        /*
            There are no collisions- insert a new speed at this time
        */

        if (ChangeTime < 0)
            continue;

        float SpeedValue;
        SpeedValue = SectionValue(tVSpeeds, ChangeTime) * Change->Value;

        TimingSegment VSpeed;

        VSpeed.Time = ChangeTime;
        VSpeed.Value = SpeedValue;

        VerticalSpeeds.push_back(VSpeed);

        /*
            Theorically, if there were a VSpeed change after this one (such as a BPM change) we've got to modify them
            if they're between this and the next speed change.

            Apparently, this behaviour is a "bug" since osu!mania resets SV changes
            after a BPM change.
        */

        if (BPMType == VSRG::Difficulty::BT_BEATSPACE) // Okay, we're an osu!mania chart, leave the resetting.
            continue;

        // We're not an osu!mania chart, so it's time to do what should be done.
        for (auto Time = VerticalSpeeds.begin();
        Time != VerticalSpeeds.end();
            ++Time)
        {
            if (Time->Time > ChangeTime)
            {
                // Two options, between two speed changes, or the last one. Second case, NextChange == Scrolls.end().
                // Otherwise, just move on
                // Last speed change
                if (NextChange == Scrolls.end())
                {
                    Time->Value = Change->Value * SectionValue(tVSpeeds, Time->Time);
                }
                else
                {
                    if (Time->Time < NextChange->Time) // Between speed changes
                        Time->Value = Change->Value * SectionValue(tVSpeeds, Time->Time);
                }
            }
        }
    }

    std::sort(VerticalSpeeds.begin(), VerticalSpeeds.end());
}
Esempio n. 3
0
void Difficulty::ProcessBPS(TimingData& BPS, double Drift)
{
    /*
        Calculate BPS. The algorithm is basically the same as VSpeeds.
        BPS time is calculated applying the offset and drift.
    */
    assert(Data != NULL);

    TimingData &StopsTiming = Data->Stops;

    BPS.clear();

    for (auto Time = Timing.begin();
    Time != Timing.end();
        ++Time)
    {
        TimingSegment Seg;

        Seg.Time = TimeFromTimingKind(Timing, StopsTiming, *Time, BPMType, Offset, Drift);
        Seg.Value = BPSFromTimingKind(Time->Value, BPMType);

        BPS.push_back(Seg);
    }

    /* Sort for justice */
    sort(BPS.begin(), BPS.end());

    if (!StopsTiming.size() || BPMType != VSRG::Difficulty::BT_BEAT) // Stops only supported in Beat mode.
        return;

    /* Here on, just working with stops. */
    for (auto Time = StopsTiming.begin();
    Time != StopsTiming.end();
        ++Time)
    {
        TimingSegment Seg;
        double TValue = TimeAtBeat(Timing, Offset + Drift, Time->Time) + StopTimeAtBeat(StopsTiming, Time->Time);
        double TValueN = TimeAtBeat(Timing, Offset + Drift, Time->Time) + StopTimeAtBeat(StopsTiming, Time->Time) + Time->Value;

        /* Initial Stop */
        Seg.Time = TValue;
        Seg.Value = 0;

        /* First, eliminate collisions. */
        for (auto k = BPS.begin(); k != BPS.end();)
        {
            if (k->Time == TValue) /* Equal? Remove the collision, leaving only the 0 in front. */
            {
                k = BPS.erase(k);

                if (k == BPS.end())
                    break;
                else continue;
            }

            ++k;
        }

        // Okay, the collision is out. Let's push our 0-speeder.
        BPS.push_back(Seg);

        // Now we find what bps to restore to.
        float bpsRestore = bps(SectionValue(Timing, Time->Time));

        for (auto k = BPS.begin(); k != BPS.end(); )
        {
            if (k->Time > TValue && k->Time <= TValueN) // So wait, there's BPM changes in between? Holy shit.
            {
                bpsRestore = k->Value; /* This is the last speed change in the interval that the stop lasts. We'll use it. */

                /* Eliminate this since we're not going to use it. */
                k = BPS.erase(k);

                if (k == BPS.end())
                    break;
                continue;
            }

            ++k;
        }

        /* Restored speed after stop */
        Seg.Time = TValueN;
        Seg.Value = bpsRestore;
        BPS.push_back(Seg);
    }

    std::sort(BPS.begin(), BPS.end());
}