internal override void UpdateGeneral() { mascot.Update(); //remove any old slider sprites that now have no transformations (off-screen to left). if (taikoSliderActiveCollection.Count > 1) { taikoSliderActiveCollection.RemoveAll(s => s.Transformations[0].Time2 < AudioEngine.Time); } if (GameBase.SixtyFramesPerSecondFrame) { foreach (pSprite p in flyingCircles) { p.Position.X += (p.InitialPosition.X - p.Position.X + 2) * 0.065f; p.Scale *= 0.965f; p.Position.Y -= p.TagNumeric / 11.5f; p.TagNumeric -= 7; if (p.TagNumeric < 70 && p.Transformations.Count < 1) { p.FadeOut(300); } if (p.TagNumeric < -32) { p.AlwaysDraw = false; } } flyingCircles.RemoveAll(p => !p.AlwaysDraw); } bool doCircleAnimation = ComboCounter.HitCombo >= 50; if (doCircleAnimation) { circlesFrame = (ComboCounter.HitCombo >= 150 ? MouthOpen(2) : MouthOpen(1)) ? 0 : 1; hitObjectManager.hitObjectsMinimal.ForEach(ho => { SliderTaiko s = ho as SliderTaiko; if (s != null) { s.sliderStartCircle.SpriteHitCircle2.CurrentFrame = circlesFrame; } else { HitCircleTaiko h = ho as HitCircleTaiko; if (h != null) { h.SpriteHitCircle2.CurrentFrame = circlesFrame; } } }); } base.UpdateGeneral(); }
protected override void AddSlider(Slider s) { SliderTaiko st = (SliderTaiko)s; //The sprites get added in the update method - so we don't need to add them here. st.SpatialLength *= 1.4f; //See 1.4x multiplication of SliderMultiplier aboove. double l = st.SpatialLength; l *= st.SegmentCount; double v2 = SliderScoringPointDistance * Beatmap.DifficultySliderTickRate; double bl = Beatmap.BeatLengthAt(st.StartTime, true); // must be TRUE here so we get the correct duration st.EndTime = st.StartTime + (int)(l / v2 * bl); double v = SliderVelocityAt(st.StartTime); bl = Beatmap.BeatLengthAt(st.StartTime, Beatmap.BeatmapVersion < 8); double skipPeriod = Math.Min( bl / Beatmap.DifficultySliderTickRate, (double)(st.EndTime - st.StartTime) / st.SegmentCount); // Only do the conversion if skipPeriod is actually above 0. It can be 0 for sliders with a length of 0 (=> EndTime == StartTime). // This avoids an endless loop. if (skipPeriod > 0 && Beatmap.PlayMode != PlayModes.Taiko && l / v * 1000 < 2 * bl) { int i = 0; for (double j = st.StartTime; j <= st.EndTime + skipPeriod / 8; j += skipPeriod) { HitCircle h; if (st.unifiedSoundAddition) { h = hitFactory.CreateHitCircle(Vector2.Zero, (int)j, false, st.SoundType, 0, SampleSet.None, SampleSet.None, CustomSampleSet.Default, 0, ""); } else { h = hitFactory.CreateHitCircle(Vector2.Zero, (int)j, false, st.SoundTypeList[i], 0, SampleSet.None, SampleSet.None, CustomSampleSet.Default, 0, ""); i = (i + 1) % st.SoundTypeList.Count; } Add(h, false); } return; } base.AddSlider(st); }
internal override void InitializeCalculations() { HpMultiplierNormal = 200 / (0.06 * HP_HIT_300 * hitObjectManager.hitObjects.FindAll(h => h is HitCircleTaiko).Count * hitObjectManager.MapDifficultyRange(hitObjectManager.Beatmap.DifficultyHpDrainRate, 0.5f, 0.75f, 0.98f)); HpMultiplierComboEnd = 0; // 200 / (0.06 * HP_HIT_300 * hitObjectManager.hitObjectsCount * 0.94); TotalHitsPossible = hitObjectManager.hitObjects.FindAll(h => !(h is SliderTaiko)).Count; if (GameBase.TestMode) { for (int i = 0; i < hitObjectManager.hitObjectsCount; i++) { HitObject h = hitObjectManager.hitObjects[i]; IncreaseScoreType type; if (h is HitCircleTaiko) { if (h.Finish) { type = IncreaseScoreType.Hit300; type |= IncreaseScoreType.TaikoLargeHitBoth; } else { type = IncreaseScoreType.Hit300; } IncreaseScoreHit(type, h); } else if (h is SliderTaiko) { SliderTaiko slider = (SliderTaiko)h; type = IncreaseScoreType.TaikoDrumRoll; if (slider.Finish) { type |= IncreaseScoreType.TaikoLargeHitBoth; } for (int j = 0; j < slider.hittablePoints.Count; j++) { IncreaseScoreHit(type, h); } continue; } else if (h is SpinnerTaiko) { SpinnerTaiko spinner = (SpinnerTaiko)h; for (int j = 0; j < spinner.rotationRequirement + 1; j++) { IncreaseScoreHit(IncreaseScoreType.TaikoDenDenHit, h); } IncreaseScoreHit(IncreaseScoreType.TaikoDenDenComplete, h); } } PlayerTest pt = player as PlayerTest; if (pt != null) { pt.testMaxScore = Player.currentScore.TotalScore; pt.testMaxCombo = ComboCounter.HitCombo; } Player.currentScore.TotalScore = 0; ComboCounter.HitCombo = 0; } hitObjectManager.hitObjects.ForEach(h => h.MaxHp = 200); //Make the graph look correct. base.InitializeCalculations(); }
internal override void OnClick(HitObject h) { HitCircleTaiko hc = h as HitCircleTaiko; SliderTaiko sl = h as SliderTaiko; SpinnerTaiko sp = h as SpinnerTaiko; if ((hc != null && hc.scoreValue > 0) || (sl != null && sl.LastHitSuccessful)) { pTexture bg; pTexture overlay; if (hc != null) { bg = hc.SpriteHitCircle1.Texture; overlay = hc.SpriteHitCircle2.Texture; } else { bg = sl.sliderStartCircle.SpriteHitCircle1.Texture; overlay = sl.sliderStartCircle.SpriteHitCircle2.Texture; } float depth = 1 - 0.03f * SpriteManager.drawOrderBwd(h != null ? h.StartTime : 0.1f) / 0.8f; pSprite s = new pSprite(bg, Fields.GamefieldWide, Origins.Centre, Clocks.Audio, HitObjectManagerTaiko.HIT_LOCATION, depth, true, h != null ? h.Colour : new Color(252, 184, 6)); s.Scale = h != null ? h.SpriteCollection[0].Scale : 0.7f; spriteManagerWidescreen.Add(s); s.InitialPosition.X = GameBase.GameField.DisplayToFieldXWide(HpBar.CurrentXPosition); s.TagNumeric = 169; flyingCircles.Add(s); s = new pSprite(overlay, Fields.GamefieldWide, Origins.Centre, Clocks.Audio, HitObjectManagerTaiko.HIT_LOCATION, depth + 0.0001f, true, Color.White); s.Scale = h != null ? h.SpriteCollection[0].Scale : 0.7f; s.InitialPosition.X = GameBase.GameField.DisplayToFieldXWide(HpBar.CurrentXPosition); s.TagNumeric = 169; spriteManagerWidescreen.Add(s); flyingCircles.Add(s); if (Player.KiaiActive) { s_KiaiGlow.Transformations.RemoveAll(t => t.Type == TransformationType.Scale); s_KiaiGlow.Transformations.Add(new Transformation(TransformationType.Scale, 0.85f, 0.7f, GameBase.Time, GameBase.Time + 80, EasingTypes.Out)); } } //where we store the old values, //we set them to false to make the compiler happy bool oldLeftButton1i = false; bool oldLeftButton2i = false; bool oldRightButton1i = false; bool oldRightButton2i = false; //temporarilly change the buttons to the right ones if relaxed is on. if (Player.Relaxing && hc != null) { oldLeftButton1i = InputManager.leftButton1i; oldLeftButton2i = InputManager.leftButton2i; oldRightButton1i = InputManager.rightButton1i; oldRightButton2i = InputManager.rightButton2i; InputManager.leftButton1i = hc.CorrectButtonIsLeft && (oldRightButton1i || oldLeftButton1i); InputManager.leftButton2i = hc.CorrectButtonIsLeft && (oldRightButton2i || oldLeftButton2i); InputManager.rightButton1i = !hc.CorrectButtonIsLeft && (oldRightButton1i || oldLeftButton1i); InputManager.rightButton2i = !hc.CorrectButtonIsLeft && (oldRightButton2i || oldLeftButton2i); } if (InputManager.leftButton1i || InputManager.leftButton2i) { ControlPoint p = hitObjectManager.Beatmap.ControlPointAt(AudioEngine.Time + 2); HitSoundInfo hitSoundInfo = new HitSoundInfo(HitObjectSoundType.Normal, AudioEngine.CurrentSampleSet, AudioEngine.CustomSamples, p.Volume, AudioEngine.CurrentSampleSet); AudioEngine.PlayHitSamples(hitSoundInfo, InputManager.leftButton1i ? -0.2f : 0.2f, true); if (InputManager.leftButton1i) { taikoInnerLeft.Transformations.Clear(); taikoInnerLeft.Transformations.Add(new Transformation(TransformationType.Fade, taikoInnerLeft.Alpha, 1, GameBase.Time, GameBase.Time + (int) ((1 - taikoInnerLeft.Alpha) * 80), EasingTypes.Out)); taikoInnerLeft.Transformations.Add(new Transformation(TransformationType.Fade, 1, 0, GameBase.Time + 100, GameBase.Time + 150)); } if (InputManager.leftButton2i) { taikoInnerRight.Transformations.Clear(); taikoInnerRight.Transformations.Add(new Transformation(TransformationType.Fade, taikoInnerRight.Alpha, 1, GameBase.Time, GameBase.Time + (int) ((1 - taikoInnerRight.Alpha) * 80), EasingTypes.Out)); taikoInnerRight.Transformations.Add(new Transformation(TransformationType.Fade, 1, 0, GameBase.Time + 100, GameBase.Time + 150)); } } if (InputManager.rightButton1i || InputManager.rightButton2i) { ControlPoint p = hitObjectManager.Beatmap.ControlPointAt(AudioEngine.Time + 2); HitSoundInfo hitSoundInfo = new HitSoundInfo(HitObjectSoundType.Clap, AudioEngine.CurrentSampleSet, AudioEngine.CustomSamples, p.Volume, AudioEngine.CurrentSampleSet); AudioEngine.PlayHitSamples(hitSoundInfo, InputManager.rightButton1i ? -0.2f : 0.2f, true); if (InputManager.rightButton1i) { taikoOuterLeft.Transformations.Clear(); taikoOuterLeft.Transformations.Add(new Transformation(TransformationType.Fade, taikoOuterLeft.Alpha, 1, GameBase.Time, GameBase.Time + (int) ((1 - taikoOuterLeft.Alpha) * 80), EasingTypes.Out)); taikoOuterLeft.Transformations.Add(new Transformation(TransformationType.Fade, 1, 0, GameBase.Time + 100, GameBase.Time + 150)); } if (InputManager.rightButton2i) { taikoOuterRight.Transformations.Clear(); taikoOuterRight.Transformations.Add(new Transformation(TransformationType.Fade, taikoOuterRight.Alpha, 1, GameBase.Time, GameBase.Time + (int) ((1 - taikoOuterRight.Alpha) * 80), EasingTypes.Out)); taikoOuterRight.Transformations.Add(new Transformation(TransformationType.Fade, 1, 0, GameBase.Time + 100, GameBase.Time + 150)); } } //return the input we just changed to the old values if (Player.Relaxing && hc != null) { InputManager.leftButton1i = oldLeftButton1i; InputManager.leftButton2i = oldLeftButton2i; InputManager.rightButton1i = oldRightButton1i; InputManager.rightButton2i = oldRightButton2i; } }
protected override void PostProcessing() { //Play-mode specific transformations if (GameBase.Mode == OsuModes.Edit) { return; } hitObjectsCount = hitObjects.Count; if (hitObjectsCount == 0) { return; } Vector2 hitLocation = HIT_LOCATION; int inLength = GameBase.WindowManager.WidthScaled - 40; const int outLengthTimewise = 300; const int outLength = 300; double multipier = 1; bool hidden = ModManager.CheckActive(ActiveMods, Mods.Hidden) && !ModManager.CheckActive(ActiveMods, Mods.HardRock); if (hidden) { inLength = WindowManager.DEFAULT_WIDTH - 40; spriteManager.SetVisibleArea(new RectangleF(0, 0, WindowManager.DEFAULT_WIDTH, GameBase.WindowManager.HeightScaled)); } if (ModManager.CheckActive(ActiveMods, Mods.HardRock)) { multipier *= 1.4f * GameBase.WindowManager.WidthScaled / WindowManager.DEFAULT_WIDTH; } else if (ModManager.CheckActive(ActiveMods, Mods.Easy)) { multipier *= 0.8f; } for (int i = 0; i < hitObjectsCount; i++) { HitObject currHitObject = hitObjects[i]; currHitObject.ModifyPosition(hitLocation); double outLengthCurr = outLength; double sv = SliderVelocityAt(currHitObject.StartTime) * multipier; if (currHitObject is SliderTaiko) { SliderTaiko s = (SliderTaiko)currHitObject; //Adjust the length before calculation to allow for the difficulty multiplier. s.UpdateCalculations(true, multipier); outLengthCurr += s.SpatialLength; } int inMsLength = (int)(inLength / sv * 1000); int outMsLength = (int)(outLengthTimewise / sv * 1000); SpinnerTaiko st = currHitObject as SpinnerTaiko; if (st != null) { //special handling of taiko spinners, where we need to show a warning icon on the taiko bar. pSprite s = st.WarningIcon; const int appearTime = 200; s.Transformations.Add( new Transformation(new Vector2(s.Position.X + inLength, s.Position.Y), new Vector2(s.Position.X, s.Position.Y), currHitObject.StartTime - inMsLength, currHitObject.StartTime)); s.Transformations.Add( new Transformation(new Vector2(s.Position.X, s.Position.Y), new Vector2(256, 196), currHitObject.StartTime, currHitObject.StartTime + appearTime)); s.Transformations.Add( new Transformation(TransformationType.Scale, 1, 3, currHitObject.StartTime, currHitObject.StartTime + appearTime, EasingTypes.Out)); s.Transformations.Add(new Transformation(TransformationType.Fade, 1, 0, currHitObject.StartTime, currHitObject.StartTime + appearTime)); } else { for (int j = 0; j < currHitObject.SpriteCollection.Count; j++) { pSprite s = currHitObject.SpriteCollection[j]; s.Transformations.Add( new Transformation(new Vector2(s.Position.X + inLength, s.Position.Y), new Vector2(s.Position.X, s.Position.Y), currHitObject.StartTime - inMsLength, currHitObject.StartTime)); s.Transformations.Add( new Transformation(new Vector2(s.Position.X, s.Position.Y), new Vector2(s.Position.X - (float)outLengthCurr, s.Position.Y), currHitObject.StartTime, currHitObject.EndTime + outMsLength)); } } } int lastHitTime = hitObjects[hitObjectsCount - 1].EndTime + 1; List <ControlPoint> tp = Beatmap.TimingPoints; if (tp == null || tp.Count == 0) { return; } int ctp = 0; double time = tp[0].Offset; double measureLength = tp[0].BeatLength * (int)tp[0].TimeSignature; //barline time closest to 0 offset time -= measureLength * (int)(time / measureLength); //start barlines from positive offset if (time < 0) { time += measureLength; } pTexture tbl = TextureManager.Load(@"taiko-barline", SkinSource.Osu); //Precalculation of barlines. while (time <= lastHitTime) { ControlPoint currpoint = tp[ctp]; if (time > currpoint.Offset || (currpoint.EffectFlags & EffectFlags.OmitFirstBarLine) == 0) { pSprite barLine = new pSprite(tbl, Fields.GamefieldWide, Origins.Centre, Clocks.Audio, hitLocation, 0.0002f, false, Color.White); barLine.Scale = 0.88f; int intTime = (int)time; double sv = SliderVelocityAt(intTime) * multipier; int inMsLength = (int)(inLength / sv * 1000); int outMsLength = (int)(outLengthTimewise / sv * 1000); spriteManager.Add(barLine); barLine.Transformations.Add( new Transformation(new Vector2(barLine.Position.X + inLength, barLine.Position.Y), new Vector2(barLine.Position.X, barLine.Position.Y), intTime - inMsLength, intTime)); barLine.Transformations.Add( new Transformation(new Vector2(barLine.Position.X, barLine.Position.Y), new Vector2(barLine.Position.X - outLength, barLine.Position.Y), intTime, intTime + outMsLength)); } double bl = currpoint.BeatLength; if (bl < 800) { bl *= (int)currpoint.TimeSignature; } time += bl; if (ctp + 1 < tp.Count && time >= tp[ctp + 1].Offset) { ctp++; time = tp[ctp].Offset; } } }
internal override void CreateAutoplayReplay() { InputManager.ReplayScore.Replay = new List <bReplayFrame>(); List <bReplayFrame> replay = InputManager.ReplayScore.Replay; bool hitButton = true; replay.Add(new bReplayFrame(-100000, 320, 240, pButtonState.None)); replay.Add(new bReplayFrame(hitObjectManager.hitObjects[0].StartTime - 1000, 320, 240, pButtonState.None)); for (int i = 0; i < hitObjectManager.hitObjectsCount; i++) { HitObject h = hitObjectManager.hitObjects[i]; pButtonState button; if (h.EndTime < InputManager.ReplayStartTime) { h.IsHit = true; continue; } SpinnerTaiko sp = h as SpinnerTaiko; if (sp != null) { int d = 0; int count = 0; int req = sp.rotationRequirement + 1; int hitRate = h.Length / req; for (int j = h.StartTime; j < h.EndTime; j += hitRate) { switch (d) { default: button = pButtonState.Left1; break; case 1: button = pButtonState.Right1; break; case 2: button = pButtonState.Left2; break; case 3: button = pButtonState.Right2; break; } replay.Add(new bReplayFrame(j, h.Position.X, h.Position.Y, button)); d = (d + 1) % 4; if (++count > req) { break; } } } else if (h is SliderTaiko) { SliderTaiko s = h as SliderTaiko; double delay = s.MinHitDelay; double time = s.StartTime; for (int j = 0; j < s.hittablePoints.Count; j++) { replay.Add(new bReplayFrame((int)time, h.Position.X, h.Position.Y, hitButton ? pButtonState.Left1 : pButtonState.Left2)); time += delay; hitButton = !hitButton; } } else { if (h.Whistle || h.Clap) { if (h.Finish) { button = pButtonState.Right1 | pButtonState.Right2; } else { button = hitButton ? pButtonState.Right1 : pButtonState.Right2; } } else { if (h.Finish) { button = pButtonState.Left1 | pButtonState.Left2; } else { button = hitButton ? pButtonState.Left1 : pButtonState.Left2; } } replay.Add(new bReplayFrame(h.StartTime, h.Position.X, h.Position.Y, button)); } replay.Add(new bReplayFrame(h.EndTime + 1, h.EndPosition.X, h.EndPosition.Y, pButtonState.None)); if (i < hitObjectManager.hitObjectsCount - 1) { int waitTime = hitObjectManager.hitObjects[i + 1].StartTime - 1000; if (waitTime > h.EndTime) { replay.Add(new bReplayFrame(waitTime, h.EndPosition.X, h.EndPosition.Y, pButtonState.None)); } } hitButton = !hitButton; } Player.currentScore.Replay = InputManager.ReplayScore.Replay; Player.currentScore.PlayerName = "mekkadosu!"; InputManager.ReplayScore.Replay.ForEach(f => { f.mouseX = -150; f.mouseY = -150; }); //Get rid of the mouse cursor for taiko autoplay. }