Rhythm Test Text Update!!! (#898)

Rhythm Test GBA now has customizable text! This can only go well!

(Also it's fuckin audible now)
This commit is contained in:
wookywok
2024-04-29 10:10:34 -05:00
committed by GitHub
parent 6f391565a8
commit 20ca0f9e2e
19 changed files with 1409 additions and 227 deletions

View File

@ -1,8 +1,10 @@
using System;
using System.Text;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using HeavenStudio.Util;
using HeavenStudio.InputSystem;
@ -37,21 +39,31 @@ namespace HeavenStudio.Games.Loaders
return new Minigame("rhythmTestGBA", "Rhythm Test (GBA) \n<color=#adadad>(Rhythm-kan Check)</color>", "2DD816", false, false, new List<GameAction>()
{
new GameAction("countin", "Start Beeping")
new GameAction("countin", "Change Screen Beeping Properties")
{
function = delegate { RhythmTestGBA.instance.KeepTheBeep(eventCaller.currentEntity.beat, eventCaller.currentEntity.length, eventCaller.currentEntity["toggle"], eventCaller.currentEntity["auto"]); },
function = delegate { RhythmTestGBA.instance.KTBPrep(eventCaller.currentEntity.beat, eventCaller.currentEntity.length, eventCaller.currentEntity["toggle"], eventCaller.currentEntity["auto"],
eventCaller.currentEntity["image"],
eventCaller.currentEntity["textFlash"], eventCaller.currentEntity["textDisplay"], eventCaller.currentEntity["hasSound"]); },
defaultLength = 1f,
resizable = true,
parameters = new List<Param>()
{
new Param("toggle", true, "Toggle", "Toggle the automatic beeping on or off."),
new Param("toggle", true, "Toggle", "Toggle the beeping on or off."),
new Param("auto", false, "Auto", "Toggle if the machine should beep automatically."),
new Param("image", RhythmTestGBA.PulseOption.Note, "Screen Image", "Set what appears on the machine's screen.", new List<Param.CollapseParam>()
{
new Param.CollapseParam((x, _) => (int)x == (int)RhythmTestGBA.PulseOption.Text, new string[] { "textFlash", "textDisplay" }),
}),
new Param("textDisplay", "Get ready...", "Text to Display", "Changes the text displayed on the screen."),
new Param("textFlash", true, "Text Flash", "Toggle if the text on the screen pulses to the beat."),
new Param("hasSound", true, "Has Sound", "Toggle if the beeping plays sound or not.")
},
},
new GameAction("button", "Start Keep-the-Beat")
{
function = delegate { var e = eventCaller.currentEntity; RhythmTestGBA.StartKeepbeat(e.beat); },
preFunction = delegate { var e = eventCaller.currentEntity; RhythmTestGBA.PreStartKeepbeat(e.beat, e.length); },
defaultLength = 1f,
resizable = false,
@ -59,12 +71,17 @@ namespace HeavenStudio.Games.Loaders
new GameAction("stopktb", "Stop Keep-the-Beat")
{
preFunction = delegate { RhythmTestGBA.instance.PreStopKeepbeat(eventCaller.currentEntity.beat, eventCaller.currentEntity.length, eventCaller.currentEntity["mutecue"]); },
preFunction = delegate { RhythmTestGBA.instance.PreStopKeepbeat(eventCaller.currentEntity.beat, eventCaller.currentEntity.length, eventCaller.currentEntity["mutecue"], eventCaller.currentEntity["finishText"], eventCaller.currentEntity["textDisplay"]); },
defaultLength = 4f,
resizable = false,
parameters = new List<Param>()
{
new Param("mutecue", false, "Mute Cue", "Mute the sound cue signifying the end of the keep-the-beat section."),
new Param("finishText", true, "Finish Text", "Set if text appears once the keep-the-bet section is finished.", new List<Param.CollapseParam>()
{
new Param.CollapseParam((x, _) => (bool)x, new string[] { "textDisplay" }),
}),
new Param("textDisplay", "Test complete!", "Text to Display", "Changes the text displayed on the screen."),
}
},
@ -105,25 +122,40 @@ namespace HeavenStudio.Games
{
/// This class handles the minigame logic.
/// Minigame inherits directly from MonoBehaviour, and adds Heaven Studio specific methods to override.
using Scripts_RhythmTestGBA;
public class RhythmTestGBA : Minigame
{
public static RhythmTestGBA instance;
static List<double> queuedButton = new();
bool goBeep;
//bool stopBeep; Unused value - Marc
bool stopAutoBeep;
bool keepPressing;
bool shouldmute;
bool disableCount;
bool beatPulseTextFlash = false;
bool beepHasSound;
bool canBeep = false;
//bool isBeeping = false;
int screenFXType;
private double numberSelect;
private float countLength;
[NonSerialized] public List<Interval> noBopIntervals = new(),
noBeepIntervals = new();
[Header("Objects")]
[SerializeField] GameObject noteFlash;
[SerializeField] TMP_Text screenText;
[Header("Animators")]
[SerializeField] Animator buttonAnimator;
[SerializeField] Animator flashAnimator;
[SerializeField] Animator numberBGAnimator;
[SerializeField] Animator numberAnimator;
[SerializeField] Animator textAnimator;
[Header("Properties")]
//private static double startBlippingBeat = double.MaxValue; Unused value - Marc
@ -136,18 +168,36 @@ namespace HeavenStudio.Games
GameEvent button = new GameEvent();
double lastButton = double.MaxValue;
// public struct QueuedButton
// {
// public double beat;
// public float length;
// }
// static List<QueuedButton> queuedButton = new List<QueuedButton>();
public enum PulseOption
{
Note,
Text
}
public enum BeepNoise: int
{
defaultBeep = 0,
highBeep = 1,
dingBeep = 2
}
public int beepType = 0;
//public struct QueuedButton
//{
// public double beat;
// public float length;
//}
//static List<QueuedButton> queuedButton = new List<QueuedButton>();
private void Awake()
{
instance = this;
screenText.text = "";
SetupBopRegion("rhythmTestGBA", "countin", "auto");
var currentBeat = Conductor.instance.unswungSongPositionInBeatsAsDouble;
KeepTheBeep(currentBeat, 1f, false, false, 0, true);
HandleBeeps();
}
void OnDestroy()
@ -208,36 +258,202 @@ namespace HeavenStudio.Games
}
}
public void KeepTheBeep(double beat, float length, bool shouldBeep, bool autoBeep)
//public override void OnGameSwitch (double beat)
//{
// var actions = GameManager.instance.Beatmap.Entities.FindAll(e => e.datamodel.Split('/')[0] == "rhythmTestGBA");
// var tempStops = actions.FindAll(e => e.datamodel == "rhythmTestGBA/stopktb");
// foreach (var e in tempStops.FindAll(e => e.beat < beat && e.beat + 2 > beat)) {
// PreStopKeepbeat(e.beat, e.length, e["mutecue"], e["textFlash"]);
// }
//}
private void HandleBeeps()
{
//stopBeep = false; Unused value - Marc
if (!shouldBeep) { goBeep = false; return;}
goBeep = autoBeep;
if (shouldBeep)
List<RiqEntity> events = EventCaller.GetAllInGameManagerList("rhythmTestGBA", new string[] { "countin" });
foreach (var e in events)
{
for (int i = 0; i < length; i++)
{
BeatAction.New(instance, new List<BeatAction.Action>()
{
new BeatAction.Action(beat + i, delegate
{
PlayFlashFX();
SoundByte.PlayOneShotGame("rhythmTestGBA/blip");
})
});
}
noBopIntervals.Add(new Interval(e.beat, e.beat + 1));
}
foreach (var v in events)
{
noBeepIntervals.Add(new Interval(v.beat, v.beat + v.length));
}
}
public void KTBPrep(double beat, float length, bool shouldBeep, bool autoBeep, int type, bool textFlash, string textDisplay, bool hasSound)
{
canBeep = true;
if (type == 1)
{
screenText.text = textDisplay;
}
beepType = 0;
screenFXType = type;
beepHasSound = hasSound;
KeepTheBeep(beat, length, shouldBeep, autoBeep, type, textFlash);
}
public void KeepTheBeep(double beat, float length, bool shouldBeep, bool autoBeep, int type, bool textFlash)
{
beatPulseTextFlash = textFlash;
if (beepHasSound)
{
switch (beepType)
{
case (int)BeepNoise.defaultBeep:
SoundByte.PlayOneShotGame("rhythmTestGBA/blip");
break;
case (int)BeepNoise.highBeep:
SoundByte.PlayOneShotGame("rhythmTestGBA/blip2");
break;
case (int)BeepNoise.dingBeep:
SoundByte.PlayOneShotGame("rhythmTestGBA/end_ding");
break;
}}
if (shouldBeep)
{
PlayFakeFlashFX(type, textFlash);
List<BeatAction.Action> beeps = new List<BeatAction.Action>();
for (int i = 0; i < length; i++)
{
beeps.Add(new BeatAction.Action(beat + i, delegate {
PlayFlashFX();}
));
}
BeatAction.New(instance, beeps);
}
}
//goBeep = autoBeep;
//if (autoBeep)
//{
// PlayFlashFX(beatPulseTextFlash, type);
// SoundByte.PlayOneShotGame("rhythmTestGBA/blip");
//}
// if (shouldBeep && !autoBeep)
// {
//if (!isBeeping)
// {
// PlayFlashFX(beatPulseTextFlash, type);
// SoundByte.PlayOneShotGame("rhythmTestGBA/blip");
// isBeeping = true;
// }
// for (int i = 0; i < length; i++)
// {
// BeatAction.New(instance, new List<BeatAction.Action>()
// {
// new BeatAction.Action(beat + i, delegate
// {
// PlayFlashFX(beatPulseTextFlash, type);
// SoundByte.PlayOneShotGame("rhythmTestGBA/blip");
// })
// });
// }
// }
// }
public void PlayFlashFX()
{
numberAnimator.Play("Idle");
numberBGAnimator.Play("Idle");
flashAnimator.Play("KTBPulse", 0 ,0);
var currentBeat = Conductor.instance.songPositionInBeatsAsDouble;
if (!noBopIntervals.Any(x => x.Contains(currentBeat)))
if (beepHasSound){
if(!noBeepIntervals.Any(x => x.Contains(currentBeat)))
{
{
switch (beepType)
{
case (int)BeepNoise.defaultBeep:
SoundByte.PlayOneShotGame("rhythmTestGBA/blip");
break;
case (int)BeepNoise.highBeep:
SoundByte.PlayOneShotGame("rhythmTestGBA/blip2");
break;
case (int)BeepNoise.dingBeep:
SoundByte.PlayOneShotGame("rhythmTestGBA/end_ding");
break;
}
}
}}
if (screenFXType == 0)
{
noteFlash.SetActive(true);
flashAnimator.DoScaledAnimationAsync("KTBPulse", 0.5f);
screenText.text = "";
}
else if (beatPulseTextFlash){
noteFlash.SetActive(false);
textAnimator.DoScaledAnimationAsync("TextFlash", 0.5f);
}
else
{
noteFlash.SetActive(false);
textAnimator.DoScaledAnimationAsync("TextIdle", 0.5f);
}
BeatAction.New(instance, new List<BeatAction.Action>()
{
new BeatAction.Action(currentBeat+0.9f, delegate {noteFlash.SetActive(false);})
});
}
public void PlayFakeFlashFX(int fakeFXType, bool textFlash)
{
numberAnimator.Play("Idle");
numberBGAnimator.Play("Idle");
var currentBeat = Conductor.instance.songPositionInBeatsAsDouble;
if (fakeFXType == 0)
{
noteFlash.SetActive(true);
flashAnimator.DoScaledAnimationAsync("KTBPulse", 0.5f);
screenText.text = "";
}
else if (textFlash){
noteFlash.SetActive(false);
textAnimator.DoScaledAnimationAsync("TextFlash", 0.5f);
}
else
{
noteFlash.SetActive(false);
textAnimator.DoScaledAnimationAsync("TextIdle", 0.5f);
}
BeatAction.New(instance, new List<BeatAction.Action>()
{
//new BeatAction.Action(beat-1, delegate {KillBeeps(beat);}),
new BeatAction.Action(currentBeat+0.9f, delegate {noteFlash.SetActive(false);})
});
}
public void ChangeText(double beat, string newText, bool newTextFlash)
{
screenText.text = newText;
beatPulseTextFlash = newTextFlash;
}
public void PressButton()
@ -248,79 +464,112 @@ namespace HeavenStudio.Games
}
public void PreStopKeepbeat(double beat, float length, bool muted)
public void PreStopKeepbeat(double beat, float length, bool muted, bool hasFinish, string finishText)
{
noBeepIntervals.Add(new Interval(beat, beat + length));
shouldmute = muted;
noBeepIntervals.Add(new Interval(beat, beat + length));
noBeepIntervals.Add(new Interval(beat, beat + length));
BeatAction.New(instance, new List<BeatAction.Action>()
{
new BeatAction.Action(beat-1, delegate {killBeeps(beat);}),
new BeatAction.Action(beat, delegate {StopKeepbeat(beat, shouldmute);})
new BeatAction.Action(beat, delegate {StopKeepbeat(beat, length, shouldmute, hasFinish, finishText);
canBeep = false;
})
});
}
public void StopKeepbeat(double beat, bool shouldmute)
public void StopKeepbeat(double beat, float length, bool shouldmute, bool hasFinish, string finishText)
{
keepPressing = false;
ScheduleInput(beat, 1f, InputAction_BasicPress, ButtonSuccess, ButtonFailure, ButtonEmpty);
ScheduleInput(beat, 2f, InputAction_BasicPress, ButtonSuccess, ButtonFailure, ButtonEmpty);
ScheduleInput(beat, 3f, InputAction_BasicPress, ButtonSuccess, ButtonFailure, ButtonEmpty);
BeatAction.New(instance, new List<BeatAction.Action>()
{
new BeatAction.Action(beat, delegate {PlayFlashFX();}),
new BeatAction.Action(beat+1, delegate {PlayFlashFX();}),
new BeatAction.Action(beat+1, delegate {PlayFlashFX();}),
new BeatAction.Action(beat+2, delegate {PlayFlashFX();}),
new BeatAction.Action(beat+2, delegate {PlayFlashFX();}),
new BeatAction.Action(beat+3, delegate { SoundByte.PlayOneShotGame("rhythmTestGBA/end_ding", beat: beat, forcePlay: true);})
new BeatAction.Action(beat+3, delegate { SoundByte.PlayOneShotGame("rhythmTestGBA/end_ding", beat: beat, forcePlay: true);
if (hasFinish)
{
screenText.text = finishText;
textAnimator.DoScaledAnimationAsync("TextIdle", 0.5f);
}
})
});
if (!shouldmute)
{
SoundByte.PlayOneShotGame("rhythmTestGBA/blip2");
BeatAction.New(instance, new List<BeatAction.Action>()
{
new BeatAction.Action(beat+1, delegate { SoundByte.PlayOneShotGame("rhythmTestGBA/blip2", beat: beat);}),
new BeatAction.Action(beat+2, delegate { SoundByte.PlayOneShotGame("rhythmTestGBA/blip2", beat: beat);})
});
MultiSound.Play(new MultiSound.Sound[] {
new MultiSound.Sound("rhythmTestGBA/blip2", beat),
new MultiSound.Sound("rhythmTestGBA/blip2", beat+1),
new MultiSound.Sound("rhythmTestGBA/blip2", beat+2),
});
}
}
public void StopKeepbeatInput(double beat)
{
ScheduleInput(beat, 0f, InputAction_BasicPress, ButtonSuccess, ButtonFailure, ButtonEmpty);
PlayFlashFX();
}
public override void OnBeatPulse(double beat)
{
if (goBeep)
if (BeatIsInBopRegion(beat) && canBeep)
{
PlayFlashFX();
SoundByte.PlayOneShotGame("rhythmTestGBA/blip");
}
}
public void killBeeps(double beat)
//public void KillBeeps(double beat)
//{
// goBeep = false;
//isBeeping = false;
//}
public static void PreStartKeepbeat(double beat, float length)
{
goBeep = false;
if (GameManager.instance.currentGame == "rhythmTestGBA")
{
StartKeepbeat(beat, length);
}
else
{
BeatAction.New(instance, new List<BeatAction.Action>()
{
new BeatAction.Action(beat, delegate {queuedButton.Add(wantButton);}),
}
);
}
}
public static void StartKeepbeat(double beat)
public static void StartKeepbeat(double beat, float length)
{
RhythmTestGBA.wantButton = beat-1;
@ -328,6 +577,7 @@ namespace HeavenStudio.Games
}
public void PreCountDown(double startBeat, float length, int countdownNumber)
{
if (keepPressing) return;
@ -667,3 +917,29 @@ namespace HeavenStudio.Games
}
}
namespace HeavenStudio.Games.Scripts_RhythmTestGBA
{
public class Interval
{
private readonly double _start;
private readonly double _end;
private readonly Func<double, double, bool> _leftComparer;
private readonly Func<double, double, bool> _rightComparer;
public double Start => _start;
public double End => _end;
public Interval(double start, double end, bool isLeftClosed = true, bool isRightClosed = false)
{
_start = start;
_end = end;
_leftComparer = isLeftClosed ? (value, boundary) => value >= boundary : (value, boundary) => value > boundary;
_rightComparer = isRightClosed ? (value, boundary) => value <= boundary : (value, boundary) => value < boundary;
}
public bool Contains(double value) => _leftComparer(value, _start) && _rightComparer(value, _end);
}
}