private void UpdateStream()
        {
            int    start    = m_slider.StartTime;
            double length   = m_slider.SpatialLength;
            double beatsnap = (double)GetBeatSnap();

            double spacing;
            int    count;

            if (radCount.Checked)
            {
                count   = (int)(numericCount.Value);
                spacing = length / (double)Math.Max(1, count - 1);
            }
            else
            {
                spacing = m_slider.Velocity * AudioEngine.BeatLengthAt(start, false) * (double)(numericDistanceSnap.Value) / (beatsnap * 1000);
                count   = (int)((length + 1.0d) / spacing) + 1;
            }

            if (spacing == lastSpacing || count == 0)
            {
                return;
            }

            double progress  = 0.0d;
            double increment = AudioEngine.BeatLengthAt(start, false) / beatsnap;
            double time      = start;

            editor.changeManager.AllowFinish = false;
            editor.Compose.DeleteSelection();
            editor.FinishOnBreakUpdate       = false;
            editor.changeManager.AllowFinish = true;

            editor.changeManager.PushAction(ChangeType.HitObject, ActionType.Add);

            bool replace = true;

            for (int x = 0; x < count; x++)
            {
                Vector2 position = m_slider.positionAtLength((float)progress);

                HitCircleOsu h = new HitCircleOsu(editor.hitObjectManager, position, (int)time, x == 0 && m_slider.NewCombo, false, false, false, 0);
                editor.hitObjectManager.Add(h, true);
                editor.Compose.Select(h);

                editor.changeManager.BackupData(h, replace);
                replace = false;

                time     += increment;
                progress += spacing;
            }
            editor.hitObjectManager.Sort(true);
            editor.BreakDirty = true;
        }
Beispiel #2
0
        internal static double TimeFromOffset(int offset)
        {
            HitObjectManager hom = null;

            if (GameBase.Mode == OsuModes.Play)
            {
                hom = Player.Instance.hitObjectManager;
            }
            else if (GameBase.Mode == OsuModes.Edit)
            {
                hom = Editor.Instance.hitObjectManager;
            }
            if (hom == null)
            {
                return(AudioEngine.BeatLengthAt(offset, BeatmapManager.Current.PlayMode == PlayModes.OsuMania));
            }
            return(hom.Beatmap.BeatLengthAt(offset, hom.Beatmap.PlayMode == PlayModes.OsuMania));
        }
        /// <summary>
        /// Beats the snap value.
        /// </summary>
        /// <param name="time">The time which should be snapped.</param>
        /// <param name="snapDivisor">The snap divisor (the bottom number of a fraction).</param>
        /// <param name="original">Assuming we want to move *away* from an old timing (ie. jump left 1 notch) set this to the original.</param>
        /// <returns></returns>
        internal int BeatSnapValue(double time, int snapDivisor, double original)
        {
            if (AudioEngine.ControlPoints.Count == 0)
            {
                return((int)time);
            }

            double offset    = AudioEngine.BeatOffsetCloseToZeroAt(original);
            double increment = AudioEngine.BeatLengthAt(original, false) / snapDivisor;

            int flooredCount;

            if (time - offset < 0)
            {
                flooredCount = (int)((time - offset) / increment) - 1;
            }
            else
            {
                flooredCount = (int)((time - offset) / increment);
            }

            int leftVal  = (int)(flooredCount * increment + offset);
            int rightVal = (int)((flooredCount + 1) * increment + offset);

            if (original != time)
            {
                if (leftVal == original)
                {
                    return(rightVal);
                }
                if (rightVal == original)
                {
                    return(leftVal);
                }
            }

            return(time - leftVal < rightVal - time ? leftVal : rightVal);
        }
        internal void BeatShiftCircle(int direction)
        {
            if (editor.Compose.selectedObjects.Count == 0)
            {
                return;
            }

            double increment = AudioEngine.BeatLengthAt(editor.Compose.selectedObjects[0].StartTime, false) / editor.BeatSnapDivisor;

            changeManager.BeginAction(ChangeType.HitObject, ActionType.MoveTimeline, Modifier.VariableChanges);
            changeManager.PushAction(ActionType.ChangeLength, Modifier.VariableChanges);
            changeManager.BackupUnusedActions(editor.Compose.selectedObjects);

            foreach (HitObject h in editor.Compose.selectedObjects)
            {
                h.ModifyTime(BeatSnapValue(h.StartTime) + (int)(direction * increment));
            }

            hitObjectManager.Sort(true);

            editor.FinishOnBreakUpdate = true;
            editor.UpdateBreaks();
        }
Beispiel #5
0
        protected override void runTimingRules()
        {
            EventManager manager = Editor.Instance.eventManager;

            List <ControlPoint> points = AudioEngine.ControlPoints.FindAll(t => t.KiaiMode == true);

            for (int i = 0; i < points.Count; i++)
            {
                if (i < points.Count - 1 && (points[i + 1].Offset - points[i].Offset) < AudioEngine.BeatLengthAt(points[i].Offset, false) * 4)
                {
                    Reports.Add(new AiReport(Severity.Error, LocalisationManager.GetString(OsuString.AITimingTaiko_KiaiToggledTooOften)));
                }
            }

            base.runTimingRules();
        }
Beispiel #6
0
        public override void Draw()
        {
            TapWindow.Draw();

            List <Line> lineList = new List <Line>();
            Vector2     vCentre  = new Vector2(330, 360);

            //Determines the size of the metronome
            float hitObjectRadius = editor.hitObjectManager.HitObjectRadius;

            ControlPoint active = AudioEngine.ActiveControlPoint;
            float        mul    = active != null ? active.BpmMultiplier : 1;                      // Avoid nullref when no sections exist.

            float dist  = (float)(100 * BeatmapManager.Current.DifficultySliderMultiplier / mul); // Length of one beat
            float count = (int)(300 / dist);                                                      // Number of beats

            // Fix for very fast slider speeds: make the slider half a beat long.
            // This fix should hold for speeds up to 6.0x
            if (count == 0)
            {
                count = 0.5f;
            }

            float   totalLength = count * dist;
            Vector2 off         = new Vector2(totalLength * 0.5f, 0);

            lineList.Add(
                new Line(GameBase.WindowManager.ApplyRatio(vCentre - off), GameBase.WindowManager.ApplyRatio(vCentre + off)));
            GameBase.LineManager.Draw(lineList, hitObjectRadius * GameBase.WindowManager.RatioInverse, backgroundColour, 0,
                                      @"Standard", true);
            lineList.Clear();

            // fix tick spacing for slider (BPM) multiplier sections
            Vector2 pointDist = new Vector2((float)editor.hitObjectManager.SliderScoringPointDistance / mul, 0);

            Vector2 cp = vCentre - off;

            // Fix rounding error causing a missing tick.
            // In a perfect world, we could use tick RATE here, not distance.
            while (cp.X <= vCentre.X + off.X + 1.0f)
            {
                lineList.Add(new Line(GameBase.WindowManager.ApplyRatio(cp), GameBase.WindowManager.ApplyRatio(cp)));
                cp += pointDist;
            }

            cp = vCentre - off;

            GameBase.LineManager.Draw(lineList, hitObjectRadius * 0.2F * editor.hitObjectManager.SpriteRatio,
                                      Color.White, 0, @"Standard",
                                      true);
            lineList.Clear();


            double first = AudioEngine.BeatOffsetAt(AudioEngine.Time);

            // AllowMultiplier: FALSE, otherwise we compensate for slider multipliers TWICE and get the wrong value.
            double f = (AudioEngine.Time - first) / AudioEngine.BeatLengthAt(AudioEngine.Time, false);

            f *= dist;
            f  = f % (totalLength * 2);

            while (f < 0)
            {
                f += totalLength;
            }

            if (f >= totalLength)
            {
                f = (totalLength * 2) - f;
            }

            cp += new Vector2((float)f, 0);

            lineList.Add(new Line(GameBase.WindowManager.ApplyRatio(cp), GameBase.WindowManager.ApplyRatio(cp)));
            GameBase.LineManager.Draw(lineList, hitObjectRadius * GameBase.WindowManager.RatioInverse, metronomeColour, 0, @"Standard", true);
        }
Beispiel #7
0
        protected virtual void runComposeRules()
        {
            circleRadius = (float)(512 / 8f * (1f - 0.7f * hitObjectManager.AdjustDifficulty(BeatmapManager.Current.DifficultyCircleSize)) / 2f) - 1;

            runSanityRules();

            List <HitObjectBase> hitObjects = hitObjectManager.GetHitObjects();

            bool   lastWasSpinner    = false;
            double slowestBeatlength = 0;

            for (int i = 0; i < hitObjects.Count; i++)
            {
                bool          isLast = i == hitObjects.Count - 1;
                HitObjectBase h      = hitObjects[i];
                HitObjectBase h1     = isLast ? null : hitObjects[i + 1];

                //check offscreen
                if (testOffScreen(h.Position))
                {
                    Reports.Add(new AiReportOneObject(h, h.StartTime, delegate { return(testOffScreen(h.Position)); }, Severity.Warning, LocalisationManager.GetString(OsuString.AICompose_ObjectOffscreen), 0));
                }

                if (h.EndPosition != h.Position && testOffScreen(h.EndPosition))
                {
                    Reports.Add(new AiReportOneObject(h, h.EndTime, delegate { return(testOffScreen(h.EndPosition)); }, Severity.Warning, LocalisationManager.GetString(OsuString.AICompose_ObjectEndOffscreen), 0));
                }

                //Check for combos over 24
                if (h.ComboNumber > 24)
                {
                    Reports.Add(new AiReportOneObject(h, h.EndTime, delegate { return(h.ComboNumber <= 24); }, Severity.Warning, LocalisationManager.GetString(OsuString.AICompose_LongCombo), -1));
                }

                if (i > 0 && !isLast)
                {
                    if (hitObjects[i].StartTime == hitObjects[i + 1].StartTime)
                    {
                        HitObjectBase last = hitObjects[i - 1];
                        Reports.Add(new AiReportTwoObjects(last, h, delegate { return(last.StartTime != h.StartTime); }, Severity.Error, LocalisationManager.GetString(OsuString.AICompose_SimultaneousObjects), -1));
                    }
                }

                if (lastWasSpinner && !(h is Spinner))
                {
                    Spinner spinner = (Spinner)hitObjects[i - 1];
                    if (spinner.StartTime > h.StartTime - hitObjectManager.PreEmpt + HitObjectManager.FadeIn)
                    {
                        Reports.Add(new AiReportTwoObjects(spinner, h, delegate() { return(spinner.StartTime <= h.StartTime - hitObjectManager.PreEmpt + HitObjectManager.FadeIn); }, Severity.Error, LocalisationManager.GetString(OsuString.AICompose_NinjaSpinner), -1));
                    }
                }

                lastWasSpinner = (h is Spinner);

                if (h is SliderOsu)
                {
                    // curve stuff is only defined for osu!mode, but happily enough, the editor is always in osu!mode.
                    SliderOsu s2 = h as SliderOsu;
                    if (s2.IsRetarded())
                    {
                        Reports.Add(new AiReportOneObject(h, h.StartTime, null, Severity.Error, LocalisationManager.GetString(OsuString.AICompose_AbnormalSlider), -1));
                    }

                    // if the mapper sets a broken tick rate but never has long enough sliders to notice it, don't warn
                    if (s2.EndTime - 1000 > s2.StartTime)
                    {
                        slowestBeatlength = Math.Max(slowestBeatlength, AudioEngine.BeatLengthAt(s2.StartTime));
                    }
                }

                //spinner length
                if (h.IsType(HitObjectType.Spinner))
                {
                    if (!h.IsType(HitObjectType.NewCombo))
                    {
                        Reports.Add(new AiReportOneObject(h, h.StartTime, null, Severity.Warning, LocalisationManager.GetString(OsuString.AICompose_SpinnerNoNewCombo), -1));
                    }

                    //look at SpinnerOsu.cs for these numbers.
                    double autoCanSpin = 0.05 * (double)(h.EndTime - h.StartTime) / Math.PI;
                    double require     = ((double)(h.EndTime - h.StartTime) / 1000 * hitObjectManager.SpinnerRotationRatio);
                    if (autoCanSpin - require < 5)
                    {
                        Reports.Add(new AiReportOneObject(h, h.StartTime, null, Severity.Warning, LocalisationManager.GetString(OsuString.AICompose_ShortSpinner), -1));
                    }
                }

                checkDistanceSpacing(h, h1, hitObjectManager);
            }
        }