Ejemplo n.º 1
0
        /// <summary>
        ///     Pastes hitobjects that are in the clipboard
        /// </summary>
        public void PasteHitObjects()
        {
            var clonedObjects = new List <HitObjectInfo>();

            var difference = (int)AudioEngine.Track.Time - Clipboard.First().StartTime;

            foreach (var h in Clipboard)
            {
                var hitObject = new HitObjectInfo()
                {
                    StartTime   = h.StartTime + difference,
                    EditorLayer = h.EditorLayer,
                    HitSound    = h.HitSound,
                    Lane        = h.Lane
                };

                if (h.IsLongNote)
                {
                    hitObject.EndTime = h.EndTime + difference;
                }

                clonedObjects.Add(hitObject);
            }

            ActionManager.Perform(new EditorActionBatchPlaceHitObjectKeys(WorkingMap, ScrollContainer, clonedObjects));
        }
Ejemplo n.º 2
0
        /// <summary>
        ///     Refreshes a bar sample based on the hitobject received.
        /// </summary>
        /// <param name="h"></param>
        public void RefreshSample(HitObjectInfo h)
        {
            var sample = GetSample(h);

            // Bar needs to be resized
            if (SampleBars.ContainsKey(sample))
            {
                var objs  = Qua.HitObjects.FindAll(x => h.StartTime / SampleTime == x.StartTime / SampleTime).ToList();
                var width = GetBarWidth(objs);
                SampleBars[sample].Width = width;
                SampleBars[sample].Tint  = GetBarColor(width);
                SampleBars[sample].X     = Width - SampleBars[sample].Width - 1;
            }
            // Bar needs to be added
            else
            {
                var objs  = Qua.HitObjects.FindAll(x => h.StartTime / SampleTime == x.StartTime / SampleTime).ToList();
                var width = GetBarWidth(objs);

                var bar = new Sprite
                {
                    Parent    = this,
                    Alignment = Alignment.BotLeft,
                    Size      = new ScalableVector2(width, 5),
                    Y         = -Height * (float)(objs.First().StartTime / SampleTime * SampleTime / AudioEngine.Track.Length) - 2,
                    Tint      = GetBarColor(width)
                };

                bar.X = Width - bar.Width - 1;
                SampleBars.Add(GetSample(objs.First()), bar);
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        ///     Plays the correct hitsounds based on the note index of the HitObjectPool.
        /// </summary>
        public static void PlayObjectHitSounds(HitObjectInfo hitObject)
        {
            // Normal
            if (hitObject.HitSound == 0 || (HitSounds.Normal & hitObject.HitSound) != 0)
            {
                SkinManager.Skin.SoundHit.CreateChannel().Play();
            }

            // Clap
            if ((HitSounds.Clap & hitObject.HitSound) != 0)
            {
                SkinManager.Skin.SoundHitClap.CreateChannel().Play();
            }

            // Whistle
            if ((HitSounds.Whistle & hitObject.HitSound) != 0)
            {
                SkinManager.Skin.SoundHitWhistle.CreateChannel().Play();
            }

            // Finish
            if ((HitSounds.Finish & hitObject.HitSound) != 0)
            {
                SkinManager.Skin.SoundHitFinish.CreateChannel().Play();
            }
        }
Ejemplo n.º 4
0
 void OnEnable()
 {
     grassPatch                = (GrassPatch)target;
     currentSelectedObject     = new HitObjectInfo();
     currentSelectedGroundVert = new GroundVert(Vector3.zero);
     Refresh();
 }
Ejemplo n.º 5
0
	public HitObjectInfo getEnemyDetected() {
		RaycastHit hitInfo;
		enemies = GameObject.FindGameObjectsWithTag("Enemy");
		foreach (GameObject enemy in enemies) {
			HitObjectInfo hitObjectInfo = new HitObjectInfo();
			//Debug.Log("Enemy transform position :: " + (enemy.transform.position));
			Vector3 rayDirection = (enemy.transform.position  - new Vector3(0.0f, 13.0f, 0.0f)) - this.transform.position;
			if (Vector3.Angle (rayDirection, this.transform.rotation * Vector3.forward) <= fieldOfView) {
				if (Physics.Raycast (this.transform.position, enemy.transform.position  - new Vector3(0.0f, 13.0f, 0.0f), out hitInfo, 100.0f)) {
					Debug.Log ("Hit Object from Falcon :: " + hitInfo.transform.name + ", " + hitInfo.transform.tag);
					if (hitInfo.transform.tag.Contains("Enemy")) {
						Debug.Log ("I have the Empire ship in my sights!");
						hitObjectInfo.setHitPoint(hitInfo.point);
						hitObjectInfo.setHitObject(hitInfo.transform.gameObject);
						return hitObjectInfo;
					} else {
						continue;
					}
				} else {
					continue;
				}
			} else {
				continue;
			}
		}

		Debug.Log ("Negative on Empire Fleet's location!!");
		return null;
	}
Ejemplo n.º 6
0
        /// <summary>
        ///     Gets the judgement of a particular hitobject in the map
        /// </summary>
        /// <param name="ho"></param>
        /// <returns></returns>
        public int GetHitObjectJudgementIndex(HitObjectInfo ho)
        {
            var index = -1;

            var total = 0;

            for (var i = 0; i < HitObjects.Count; i++)
            {
                if (HitObjects[i] == ho)
                {
                    return(total);
                }

                if (HitObjects[i].IsLongNote)
                {
                    total += 2;
                }
                else
                {
                    total += 1;
                }
            }

            return(index);
        }
Ejemplo n.º 7
0
        /// <summary>
        ///     Gets a hitobject at a particular judgement index
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public HitObjectInfo GetHitObjectAtJudgementIndex(int index)
        {
            HitObjectInfo h = null;

            var total = 0;

            for (var i = 0; i < HitObjects.Count; i++)
            {
                total += 1;

                if (total - 1 == index)
                {
                    h = HitObjects[i];
                    break;
                }

                if (HitObjects[i].IsLongNote)
                {
                    total += 1;
                }

                if (total - 1 == index)
                {
                    h = HitObjects[i];
                    break;
                }
            }

            return(h);
        }
Ejemplo n.º 8
0
    void HandleInput(Event e)
    {
        if (e.type == EventType.MouseDown && e.button == 0 && e.modifiers == EventModifiers.Control)
        {
            currentSelectedObject = ObjectUnderMouse();
        }

        if (e.type == EventType.MouseDown && e.button == 0 && e.modifiers == EventModifiers.Shift)
        {
            if (currentSelectedObject.transform != null)
            {
                SelectNearestVertex();
            }
        }

        // to prevent from deselection //
        if (grassPatch == null)
        {
            return;
        }
        if (Selection.activeGameObject != grassPatch.transform.gameObject)
        {
            Selection.activeGameObject = grassPatch.transform.gameObject;
        }
    }
Ejemplo n.º 9
0
 /// <summary>
 ///     Plays the correct keysounds based on the note index of the HitObjectPool.
 /// </summary>
 public static void PlayObjectKeySounds(HitObjectInfo hitObject)
 {
     foreach (var keySound in hitObject.KeySounds)
     {
         CustomAudioSampleCache.Play(keySound.Sample - 1, keySound.Volume);
     }
 }
Ejemplo n.º 10
0
 /// <summary>
 ///     Ctor -
 /// </summary>
 /// <param name="hitObject"></param>
 /// <param name="type"></param>
 /// <param name="time"></param>
 /// <param name="keys"></param>
 public ReplayAutoplayFrame(HitObjectInfo hitObject, ReplayAutoplayFrameType type, int time, ReplayKeyPressState keys)
 {
     HitObject = hitObject;
     Type      = type;
     Time      = time;
     Keys      = keys;
 }
Ejemplo n.º 11
0
        /// <summary>
        ///     Adds a HitObject sprite to the container.
        /// </summary>
        public void AddHitObjectSprite(HitObjectInfo h)
        {
            DrawableEditorHitObject hitObject;

            var skin  = SkinManager.Skin.Keys[Ruleset.WorkingMap.Mode];
            var index = skin.ColorObjectsBySnapDistance ? HitObjectManager.GetBeatSnap(h, h.GetTimingPoint(Ruleset.WorkingMap.TimingPoints)) : 0;

            if (h.IsLongNote)
            {
                if (ConfigManager.EditorViewLayers.Value)
                {
                    hitObject = new DrawableEditorHitObjectLong(this, h,
                                                                skin.EditorLayerNoteHitObjects[h.Lane - 1],
                                                                skin.EditorLayerNoteHoldBodies[h.Lane - 1],
                                                                skin.EditorLayerNoteHoldEnds[h.Lane - 1]);
                }
                else
                {
                    hitObject = new DrawableEditorHitObjectLong(this, h,
                                                                skin.NoteHoldHitObjects[h.Lane - 1][index],
                                                                skin.NoteHoldBodies[h.Lane - 1].First(),
                                                                skin.NoteHoldEnds[h.Lane - 1]);
                }
            }
            else
            {
                if (ConfigManager.EditorViewLayers.Value)
                {
                    hitObject = new DrawableEditorHitObject(this, h, skin.EditorLayerNoteHitObjects[h.Lane - 1]);
                }
                else
                {
                    hitObject = new DrawableEditorHitObject(this, h, skin.NoteHitObjects[h.Lane - 1][index]);
                }
            }

            hitObject.Alignment = Alignment.TopLeft;
            hitObject.X         = ScreenRectangle.X + LaneSize * (h.Lane - 1) + DividerLineWidth;
            hitObject.Width     = LaneSize - DividerLineWidth;

            // Make sure the width of the long note is updated if this object is indeed an LN.
            if (hitObject is DrawableEditorHitObjectLong longNote)
            {
                longNote.Body.Width = hitObject.Width;
                longNote.Tail.Width = hitObject.Width;
            }

            hitObject.AppearAsActive();

            // Check if the layer is hidden that the user is adding the object to and display the object
            // as that appropriate colour.
            if (((EditorScreenView)Ruleset.Screen.View).LayerCompositor.ScrollContainer.AvailableItems[hitObject.Info.EditorLayer].Hidden)
            {
                hitObject.AppearAsHiddenInLayer();
            }

            lock (HitObjects)
                HitObjects.Add(hitObject);
        }
Ejemplo n.º 12
0
        /// <inheritdoc />
        /// <summary>
        ///     Ctor -
        /// </summary>
        /// <param name="ruleset"></param>
        /// <param name="info"></param>
        public GameplayHitObjectKeys(HitObjectInfo info, GameplayRulesetKeys ruleset, HitObjectManagerKeys manager)
        {
            HitObjectManager = manager;
            Ruleset          = ruleset;

            InitializeSprites(ruleset, info.Lane - 1);
            InitializeObject(manager, info);
        }
 /// <inheritdoc />
 /// <summary>
 /// </summary>
 /// <param name="container"></param>
 /// <param name="info"></param>
 /// <param name="texHead"></param>
 /// <param name="texBody"></param>
 /// <param name="texTail"></param>
 public DrawableEditorHitObjectLong(EditorScrollContainerKeys container, HitObjectInfo info, Texture2D texHead,
                                    Texture2D texBody, Texture2D texTail) : base(container, info, texHead)
 {
     TextureBody = texBody;
     TextureTail = texTail;
     CreateLongNoteSprite();
     SelectionSprite.Parent    = Body;
     SelectionSprite.Alignment = Alignment.MidLeft;
 }
Ejemplo n.º 14
0
        /// <summary>
        ///     Resizes a long note with that given hitobject info.
        /// </summary>
        /// <param name="h"></param>
        public DrawableEditorHitObjectLong ResizeLongNote(HitObjectInfo h)
        {
            var note = HitObjects.Find(x => x.Info == h);

            if (note is DrawableEditorHitObjectLong n)
            {
                n.ResizeLongNote();
            }

            return(note as DrawableEditorHitObjectLong);
        }
Ejemplo n.º 15
0
        /// <inheritdoc />
        /// <summary>
        /// </summary>
        /// <param name="container"></param>
        /// <param name="info"></param>
        /// <param name="texHead"></param>
        public DrawableEditorHitObject(EditorScrollContainerKeys container, HitObjectInfo info, Texture2D texHead)
        {
            Container = container;
            Info      = info;
            Image     = texHead;
            SetHeight();
            DestroyIfParentIsNull = false;
            SetPositionY();

            CreateSelectionSprite();
        }
Ejemplo n.º 16
0
        /// <inheritdoc />
        /// <summary>
        ///     Ctor -
        /// </summary>
        /// <param name="ruleset"></param>
        /// <param name="info"></param>
        public GameplayHitObjectKeys(HitObjectInfo info, GameplayRulesetKeys ruleset, HitObjectManagerKeys manager)
        {
            HitObjectManager = manager;
            Ruleset          = ruleset;

            var lane      = info.Lane - 1;
            var playfield = (GameplayPlayfieldKeys)ruleset.Playfield;

            LongNoteSizeDifference = playfield.LongNoteSizeAdjustment[lane];
            InitializeSprites(ruleset, lane, playfield.ScrollDirections[lane]);
            InitializeObject(manager, info);
        }
Ejemplo n.º 17
0
 /// <summary>
 ///     Ctor
 /// </summary>
 /// <param name="type"></param>
 /// <param name="keyPressType"></param>
 /// <param name="hitObject"></param>
 /// <param name="songPos"></param>
 /// <param name="judgement"></param>
 /// <param name="hitDifference"></param>
 /// <param name="acc"></param>
 /// <param name="health"></param>
 public HitStat(HitStatType type, KeyPressType keyPressType, HitObjectInfo hitObject, int songPos,
                Judgement judgement, int hitDifference, double acc, float health)
 {
     HitObject     = hitObject;
     SongPosition  = songPos;
     Judgement     = judgement;
     HitDifference = hitDifference;
     Accuracy      = acc;
     Health        = health;
     Type          = type;
     KeyPressType  = keyPressType;
 }
Ejemplo n.º 18
0
    HitObjectInfo ObjectUnderMouse()
    {
        Ray           ray        = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
        RaycastHit    hit        = new RaycastHit();
        HitObjectInfo objectInfo = new HitObjectInfo();

        if (Physics.Raycast(ray, out hit))
        {
            objectInfo.transform = hit.transform;
            objectInfo.hitPoint  = hit.point;
        }

        return(objectInfo);
    }
Ejemplo n.º 19
0
        public static HitObject QuaHitToManiaHit(HitObjectInfo quaHit, int keyMode)
        {
            HitObject maniaHit;
            int       xfix = 512 / keyMode;

            if (quaHit.IsLongNote)
            {
                maniaHit = new HitObject((quaHit.Lane) * xfix - (xfix / 2), quaHit.StartTime, true, quaHit.EndTime);
            }
            else
            {
                maniaHit = new HitObject((quaHit.Lane) * xfix - (xfix / 2), quaHit.StartTime);
            }

            return(maniaHit);
        }
Ejemplo n.º 20
0
    private List <HitObjectInfo> GetHitObjectsFromGaze(Vector3 gazeOrigin, Vector3 gazeDirection)
    {
        RaycastHit[] hitColliders = Physics.RaycastAll(gazeOrigin, gazeDirection);

        List <HitObjectInfo> hitObjectInfoList = new List <HitObjectInfo>();

        foreach (var colliderhit in hitColliders)
        {
            HitObjectInfo hitInfo = new HitObjectInfo();
            hitInfo.ObjectName        = colliderhit.collider.gameObject.name;
            hitInfo.HitObjectPosition = colliderhit.collider.transform.position;
            hitInfo.HitPointOnObject  = colliderhit.point;
            hitObjectInfoList.Add(hitInfo);
        }

        return(hitObjectInfoList);
    }
Ejemplo n.º 21
0
        /// <summary>
        ///     Removes a HitObject sprite at a given index.
        /// </summary>
        public void RemoveHitObjectSprite(HitObjectInfo h)
        {
            lock (HitObjects)
            {
                var ho = HitObjects?.Find(x => x.Info == h);

                HitObjects?.Remove(ho);

                if (ho != null)
                {
                    ho.IsInView = false;
                    ho?.Destroy();
                }

                HitObjects = HitObjects.OrderBy(x => x.Info.StartTime).ToList();
            }
        }
Ejemplo n.º 22
0
        public HitObject(HitObjectInfo hitObject, int keyCount, bool dontUseOffset)
        {
            var offset = dontUseOffset ? 0 : Osu.OsuBeatmap.QUAVER_TO_OSU_OFFSET;

            Time      = hitObject.StartTime + offset;
            XPosition = 512 * hitObject.Lane / keyCount - 64;
            if (hitObject.IsLongNote)
            {
                Type    = 1 << 7;
                EndTime = hitObject.EndTime + offset;
            }
            else
            {
                Type = 1 << 0;
            }
            // TODO: Hitsounds
        }
Ejemplo n.º 23
0
    private List <HitObjectInfo> GetFirstHitObjectFromGaze(Vector3 gazeOrigin, Vector3 gazeDirection, float distance)
    {
        RaycastHit hit;
        bool       hitColliders = Physics.Raycast(gazeOrigin, gazeDirection, out hit, distance);

        List <HitObjectInfo> hitObjectInfoList = new List <HitObjectInfo>();

        if (hitColliders)
        {
            HitObjectInfo hitInfo = new HitObjectInfo();
            hitInfo.ObjectName        = hit.collider.gameObject.name;
            hitInfo.HitObjectPosition = hit.collider.transform.position;
            hitInfo.HitPointOnObject  = hit.point;
            hitObjectInfoList.Add(hitInfo);
        }

        return(hitObjectInfoList);
    }
Ejemplo n.º 24
0
        /// <summary>
        ///     Returns color of note beatsnap
        /// </summary>
        /// <param name="info"></param>
        /// <param name="timingPoint"></param>
        /// <returns></returns>
        public static int GetBeatSnap(HitObjectInfo info, TimingPointInfo timingPoint)
        {
            // Add 2ms offset buffer space to offset and get beat length
            var pos        = info.StartTime - timingPoint.StartTime + 2;
            var beatlength = 60000 / timingPoint.Bpm;

            // subtract pos until it's less than beat length. multiple loops for efficiency
            while (pos >= beatlength * (1 << 16))
            {
                pos -= beatlength * (1 << 16);
            }
            while (pos >= beatlength * (1 << 12))
            {
                pos -= beatlength * (1 << 12);
            }
            while (pos >= beatlength * (1 << 8))
            {
                pos -= beatlength * (1 << 8);
            }
            while (pos >= beatlength * (1 << 4))
            {
                pos -= beatlength * (1 << 4);
            }
            while (pos >= beatlength)
            {
                pos -= beatlength;
            }

            // Calculate Note's snap index
            var index = (int)(Math.Floor(48 * pos / beatlength));

            // Return Color of snap index
            for (var i = 0; i < 8; i++)
            {
                if (index % BeatSnaps[i] == 0)
                {
                    return(i);
                }
            }

            // If it's not snapped to 1/16 or less, return 1/48 snap color
            return(8);
        }
Ejemplo n.º 25
0
        /// <summary>
        ///     Initialize Object when created/recycled within its object pool.
        /// </summary>
        /// <param name="info"></param>
        /// <param name="manager"></param>
        public void InitializeObject(HitObjectManagerKeys manager, HitObjectInfo info)
        {
            var playfield = (GameplayPlayfieldKeys)Ruleset.Playfield;

            HitPosition = info.IsLongNote ? playfield.HoldHitPositionY[info.Lane - 1] : playfield.HitPositionY[info.Lane - 1];
            Info        = info;

            // Update Hit Object State
            HitObjectSprite.Image   = GetHitObjectTexture(info.Lane, manager.Ruleset.Mode);
            HitObjectSprite.Visible = true;
            HitObjectSprite.Tint    = Color.White;
            InitialTrackPosition    = manager.GetPositionFromTime(Info.StartTime);
            CurrentlyBeingHeld      = false;
            StopLongNoteAnimation();

            // Update hit body's size to match image ratio
            HitObjectSprite.Size = new ScalableVector2(playfield.LaneSize, playfield.LaneSize * HitObjectSprite.Image.Height / HitObjectSprite.Image.Width);
            LongNoteBodyOffset   = HitObjectSprite.Height / 2;

            // Update Hit Object State depending if its an LN or not
            if (!Info.IsLongNote)
            {
                LongNoteEndSprite.Visible    = false;
                LongNoteBodySprite.Visible   = false;
                InitialLongNoteTrackPosition = InitialTrackPosition;
            }
            else
            {
                LongNoteBodySprite.Tint      = Color.White;
                LongNoteEndSprite.Tint       = Color.White;
                LongNoteEndSprite.Visible    = SkinManager.Skin.Keys[Ruleset.Mode].DrawLongNoteEnd;
                LongNoteBodySprite.Visible   = true;
                InitialLongNoteTrackPosition = manager.GetPositionFromTime(Info.EndTime);
                UpdateLongNoteSize(InitialTrackPosition);
                InitialLongNoteSize = CurrentLongNoteSize;
            }

            // Update Positions
            UpdateSpritePositions(manager.CurrentTrackPosition);
        }
Ejemplo n.º 26
0
        /// <summary>
        ///     Returns color of note beatsnap
        /// </summary>
        /// <param name="info"></param>
        /// <param name="timingPoint"></param>
        /// <returns></returns>
        public static int GetBeatSnap(HitObjectInfo info, TimingPointInfo timingPoint)
        {
            // Add 2ms offset buffer space to offset and get beat length
            var pos        = info.StartTime - timingPoint.StartTime + 0;
            var beatlength = 60000 / timingPoint.Bpm;

            // Calculate Note's snap index
            var index = Math.Round(48 * pos / beatlength, MidpointRounding.AwayFromZero);

            // Return Color of snap index
            for (var i = 0; i < 8; i++)
            {
                // ReSharper disable once CompareOfFloatsByEqualityOperator
                if (index % BeatSnaps[i] == 0)
                {
                    return(i);
                }
            }

            // If it's not snapped to 1/16 or less, return 1/48 snap color
            return(8);
        }
Ejemplo n.º 27
0
        /// <summary>
        ///     Places a HitObject at a given lane.
        /// </summary>
        /// <param name="inputDevice"></param>
        /// <param name="lane"></param>
        /// <param name="time"></param>
        private void PlaceObject(CompositionInputDevice inputDevice, int lane, double time)
        {
            var am = ActionManager as EditorActionManagerKeys;

            if (HandlePendingLongNoteReleases(lane, time))
            {
                return;
            }

            // Find an existing object in the current lane at the same time, so we can determine if
            // the object should be placed or deleted accordingly.
            HitObjectInfo           existingObject = null;
            DrawableEditorHitObject hoveredObject  = null;

            switch (inputDevice)
            {
            case CompositionInputDevice.Keyboard:
                existingObject = WorkingMap.HitObjects.Find(x => x.StartTime == (int)time && x.Lane == lane);
                break;

            case CompositionInputDevice.Mouse:
                hoveredObject = ScrollContainer.GetHoveredHitObject();

                if (hoveredObject != null)
                {
                    existingObject = hoveredObject.Info;
                }
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(inputDevice), inputDevice, null);
            }

            // There's no object currently at this position, so add it.
            if (existingObject == null)
            {
                switch (CompositionTool.Value)
                {
                case EditorCompositionTool.Note:
                    am?.PlaceHitObject(lane, time);
                    break;

                case EditorCompositionTool.LongNote:
                    am?.PlaceLongNote(lane, time);

                    // Makes sure the long note is marked as pending, so any future objects placed in this lane
                    // will be awarded to this LN's end.
                    var workingObject = WorkingMap.HitObjects.Find(x => x.StartTime == (int)time && x.Lane == lane);
                    PendingLongNoteReleases[lane - 1] = workingObject;

                    // Make the long note appear as inactive/dead. Gives a visual effect to the user that
                    // they need to do something with the note.
                    if (!(ScrollContainer.HitObjects.Find(x => x.Info == workingObject) is DrawableEditorHitObjectLong drawable))
                    {
                        return;
                    }

                    drawable.AppearAsInactive();

                    if (!GaveLongNoteGuide)
                    {
                        NotificationManager.Show(NotificationLevel.Info, "Scroll through the timeline and place the end of the long note.");
                        GaveLongNoteGuide = true;
                    }
                    break;

                default:
                    NotificationManager.Show(NotificationLevel.Error, "This tool isn't implemented yet. Choose another!");
                    break;
                }
            }
            // An object exists, so delete it.
            else
            {
                switch (inputDevice)
                {
                case CompositionInputDevice.Keyboard:
                    am?.DeleteHitObject(existingObject);
                    break;

                case CompositionInputDevice.Mouse:
                    // hoveredObject?.AppearAsSelected();
                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(inputDevice), inputDevice, null);
                }
            }
        }
Ejemplo n.º 28
0
 public AutoModIssueExcessiveBreakTime(HitObjectInfo hitObject) : base(AutoModIssueLevel.Ranking)
 {
     HitObject = hitObject;
     Text      = $"The map contains 30 seconds or more of break time at: {HitObject.StartTime} ms.";
 }
Ejemplo n.º 29
0
        /// <summary>
        ///     Replaces regular notes with long notes and vice versa.
        ///
        ///     HitObjects and TimingPoints MUST be sorted by StartTime prior to calling this method,
        ///     see <see cref="Sort()"/>.
        /// </summary>
        public void ApplyInverse()
        {
            // Minimal LN and gap lengths in milliseconds.
            //
            // Ideally this should be computed in a smart way using the judgements so that it is always possible to get
            // perfects, but making map mods depend on the judgements (affected by strict/chill/accuracy adjustments) is
            // a really bad idea. I'm setting these to values that will probably work fine for the majority of the
            // cases.
            const int MINIMAL_LN_LENGTH  = 36;
            const int MINIMAL_GAP_LENGTH = 36;

            var newHitObjects = new List <HitObjectInfo>();

            // An array indicating whether the currently processed HitObject is the first in its lane.
            var firstInLane = new bool[GetKeyCount()];

            for (var i = 0; i < firstInLane.Length; i++)
            {
                firstInLane[i] = true;
            }

            for (var i = 0; i < HitObjects.Count; i++)
            {
                var currentObject = HitObjects[i];

                // Find the next and second next hit object in the lane.
                HitObjectInfo nextObjectInLane = null, secondNextObjectInLane = null;
                for (var j = i + 1; j < HitObjects.Count; j++)
                {
                    if (HitObjects[j].Lane == currentObject.Lane)
                    {
                        if (nextObjectInLane == null)
                        {
                            nextObjectInLane = HitObjects[j];
                        }
                        else
                        {
                            secondNextObjectInLane = HitObjects[j];
                            break;
                        }
                    }
                }

                var isFirstInLane = firstInLane[currentObject.Lane - 1];
                firstInLane[currentObject.Lane - 1] = false;

                // If this is the only object in its lane, keep it as is.
                if (nextObjectInLane == null && isFirstInLane)
                {
                    newHitObjects.Add(currentObject);
                    continue;
                }

                // Figure out the time gap between the end of the LN which we'll create and the next object.
                int?timeGap = null;
                if (nextObjectInLane != null)
                {
                    var   timingPoint = GetTimingPointAt(nextObjectInLane.StartTime);
                    float bpm;

                    // If the timing point starts at the next object, we want to use the previous timing point's BPM.
                    // For example, consider a fast section of the map transitioning into a very low BPM ending starting
                    // with the next hit object. Since the LN release and the gap are still in the fast section, they
                    // should use the fast section's BPM.
                    if ((int)Math.Round(timingPoint.StartTime) == nextObjectInLane.StartTime)
                    {
                        var prevTimingPointIndex = TimingPoints.FindLastIndex(x => x.StartTime < timingPoint.StartTime);

                        // No timing points before the object? Just use the first timing point then, it has the correct
                        // BPM.
                        if (prevTimingPointIndex == -1)
                        {
                            prevTimingPointIndex = 0;
                        }

                        bpm = TimingPoints[prevTimingPointIndex].Bpm;
                    }
                    else
                    {
                        bpm = timingPoint.Bpm;
                    }

                    // The time gap is quarter of the milliseconds per beat.
                    timeGap = (int?)Math.Max(Math.Round(15000 / bpm), MINIMAL_GAP_LENGTH);
                }

                // Summary of the changes:
                // Regular 1 -> Regular 2 => LN until 2 - time gap
                // Regular 1 -> LN 2      => LN until 2
                //      LN 1 -> Regular 2 => LN from 1 end until 2 - time gap
                //      LN 1 -> LN 2      => LN from 1 end until 2
                //
                // Exceptions:
                // - last LNs are kept (treated as regular 2)
                // - last regular objects are removed and treated as LN 2

                if (currentObject.IsLongNote)
                {
                    // LNs before regular objects are changed so they start where they ended and end a time gap before
                    // the object.
                    // LNs before LNs do the same but without a time gap.

                    if (nextObjectInLane == null)
                    {
                        // If this is the last object in its lane, though, then it's probably a better idea
                        // to leave it be. For example, finishing long LNs in charts.
                    }
                    else
                    {
                        currentObject.StartTime = currentObject.EndTime; // (this part can mess up the ordering)
                        currentObject.EndTime   = nextObjectInLane.StartTime - timeGap.Value;

                        // Clear the keysounds as we're moving the start, so they won't make sense.
                        currentObject.KeySounds = new List <KeySoundInfo>();

                        // If the next object is not an LN and it's the last object in the lane, or if it's an LN and
                        // not the last object in the lane, create a regular object at the next object's start position.
                        if ((secondNextObjectInLane == null) != nextObjectInLane.IsLongNote)
                        {
                            currentObject.EndTime = nextObjectInLane.StartTime;
                        }

                        // Filter out really short LNs or even negative length resulting from jacks or weird BPM values.
                        if (currentObject.EndTime - currentObject.StartTime < MINIMAL_LN_LENGTH)
                        {
                            // These get skipped entirely.
                            //
                            // Actually, there can be a degenerate pattern of multiple LNs with really short gaps
                            // in between them (less than MINIMAL_LN_LENGTH), which this logic will convert
                            // into nothing. That should be pretty rare though.
                            continue;
                        }
                    }
                }
                else
                {
                    // Regular objects are replaced with LNs starting from their start and ending quarter of a beat
                    // before the next object's start.
                    if (nextObjectInLane == null)
                    {
                        // If this is the last object in lane, though, then it's not included, and instead the previous
                        // LN spans up to this object's StartTime.
                        continue;
                    }

                    currentObject.EndTime = nextObjectInLane.StartTime - timeGap.Value;

                    // If the next object is not an LN and it's the last object in the lane, or if it's an LN and
                    // not the last object in the lane, this LN should span until its start.
                    if ((secondNextObjectInLane == null) == (nextObjectInLane.EndTime == 0))
                    {
                        currentObject.EndTime = nextObjectInLane.StartTime;
                    }

                    // Filter out really short LNs or even negative length resulting from jacks or weird BPM values.
                    if (currentObject.EndTime - currentObject.StartTime < MINIMAL_LN_LENGTH)
                    {
                        // These get converted back into regular objects.
                        currentObject.EndTime = 0;
                    }
                }

                newHitObjects.Add(currentObject);
            }

            // LN conversion can mess up the ordering, so sort it again. See the (this part can mess up the ordering)
            // comment above.
            HitObjects = newHitObjects.OrderBy(x => x.StartTime).ToList();
        }
 /// <summary>
 /// </summary>
 /// <param name="container"></param>
 /// <param name="hitObject"></param>
 public EditorActionDeleteHitObjectKeys(EditorScrollContainerKeys container, HitObjectInfo hitObject)
 {
     Container = container;
     HitObject = hitObject;
 }
Ejemplo n.º 31
0
 public AutoModIssueShortLongNote(HitObjectInfo hitObject) : base(AutoModIssueLevel.Ranking)
 {
     HitObject = hitObject;
     Text      = $"The long note in column {HitObject.Lane} at {HitObject.StartTime} is less than {AutoMod.ShortLongNoteThreshold} ms.";
 }