HeavenStudio/Assets/Scripts/Games/Lockstep/Lockstep.cs
Rapandrasmus 98835c3936
Title Screen (#454)
* Barebones title screen prefab added

* logo and stuff

* cool

* Added sfx to title screen

* The logo now bops to the beat

* epic reveal

* Fixed something

* put some of the stuff into the main menu

* other logo bop

* Implemented logobop2 and starbop

* added scrolling bg, tweaked positioning and wip splash text for play button

* more menu

* ooops

* Expand implemented

* cool

* Made stars spawn in in the opening

* make UI elements look nicer on different aspect ratios

* add sound while hovering over logo

* add settings menu to title screen

make the title screen properly play after the opening

* swap out title screen hover sound

remove the old config path warning

* every button works, some play mode fixes

* fix issues with beataction/multisound and pausing

* fix dropdown menus not working in certain screens

* fix particles rotating when camera controls are used

* touch style pause menu items only trigger if cursor is over an item

* various changes

make playback (unpausing) more reliable
only apply changes to advanced audio settings on launch
fix title screen visuals
add opening music
continue past opening by pressing a key
update credits

* almost forgot this

* lol

* initial flow mems

* user-taggable fonts in textboxes

* alt materials for kurokane

* assets prep

* plan out judgement screen layout

change sound encodings

* start sequencing judgement

* judgement screen sequence

* full game loop

* fix major issue with pooled sound objects

rebalance ranking audio
fix issues with some effects in play mode

* new graphics

* particles

* make certain uses of the beat never go below 0

fix loop of superb music

* make markers non clamped

lockstep frees rendertextures when unloading

* lockstep creates its own rendertextures

swapped button order on title screen
added null checks to animation helpers
disabled controller auto-search for now

* enable particles on OK rank

* play mode info panel

* let play mode handle its own fade out

* fix that alignment bug in controller settings

* more safety here

* Update PauseMenu.cs

* settable (one-liner) rating screen text

* address minigame loading crashes

* don't do this twice

* wav converter for mp3

* Update Minigames.cs

* don't double-embed the converted audio

* studio dance bugfixing spree

* import redone sprites for studio dance

* update jukebox

prep epilogue screen

* epilogue screen

* studio dance inkling shuffle test

* new studio dance choreo system

* markers upgrade

* fix deleting volume changes and markers

prep category markers

* Update Editor.unity

* new rating / epilogue settings look

* update to use new tooltip system

mark certain editor components as blocking

* finish category system

* dedicated tempo / volume marker dialogs

* swing prep

* open properties dialog if mapper hasn't opened it prior for this chart

fix memory copy bug when making new chart

* fix ctrl + s

* return to title screen button

* make graphy work everywhere

studio dance selector
membillion mems

* make sure riq cache is clear when loading chart

* lol

* fix the stupid

* bring back tempo and volume change scrolling

* new look for panels

* adjust alignment

* round tooltip

* alignment of chart property prefab

* change scale factor of mem

* adjust open captions material

no dotted BG in results commentary (only epilogue)
bugfix for tempo / volume scroll

* format line 2 of judgement a bit better

update font

* oops

* adjust look of judgement score bar

* new rating bar

* judgement size adjustment

* fix timing window scaling with song pitch

* proper clamping in dialogs

better sync conductor to dsptime (experiment)

* disable timeline pitch change when song is paused

enable perfect challenge if no marker is set to do so

* new app icon

* timing window values are actually double now

* improve deferred timekeep even more

* re-generate font atlases

new app icon in credits

* default epilogue images

* more timing window adjustment

* fix timing display when pitched

* use proper terminology here

* new logo on titlescreen

* remove wip from play

update credits

* adjust spacing of play mode panel

* redo button spacing

* can pass title screen with any controller

fix issues with controller auto-search

* button scale fixes

* controller title screen nav

* remove song genre from properties editor

* disable circle cursor when not using touch style

* proper selection graphic

remove refs
re-add heart to the opening

* controller support in opening

---------

Co-authored-by: ev <85412919+evdial@users.noreply.github.com>
Co-authored-by: minenice55 <star.elementa@gmail.com>
Co-authored-by: ThatZeoMan <67521686+ThatZeoMan@users.noreply.github.com>
2023-12-26 05:22:51 +00:00

812 lines
32 KiB
C#

/* I do not know crap about Unity or C#
Almost none of this code is mine, but it's all fair game when the game you're stealing from
borrowed from other games */
//Don't worry Raffy everyone starts somewhere - Rasmus
using HeavenStudio.Util;
using Jukebox;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
namespace HeavenStudio.Games.Loaders
{
using static Minigames;
public static class NtrBackbeatLoader
{
public static Minigame AddGame(EventCaller eventCaller)
{
return new Minigame("lockstep", "Lockstep", "f0338d", false, false, new List<GameAction>()
{
new GameAction("bop", "Bop")
{
function = delegate { var e = eventCaller.currentEntity; Lockstep.instance.Bop(e.beat, e.length, e["toggle"], e["toggle2"]); },
resizable = true,
parameters = new List<Param>()
{
new Param("toggle", true, "Bop", "Should the stepswitchers bop?"),
new Param("toggle2", false, "Bop (Auto)", "Should the stepswitchers auto bop?"),
},
},
new GameAction("stepping", "Stepping")
{
preFunction = delegate {var e = eventCaller.currentEntity; Lockstep.Marching(e.beat, e["sound"], e["amount"], e["visual"]);},
parameters = new List<Param>()
{
new Param("sound", false, "Sound", "Hai if onbeat, ho if offbeat.", new List<Param.CollapseParam>()
{
new Param.CollapseParam((x, _) => (bool)x, new string[] { "amount" })
}),
new Param("amount", new EntityTypes.Integer(1, 50, 1), "Sound Amount", "How many sounds will play consecutively?"),
new Param("visual", true, "Background Visual")
},
preFunctionLength = 1
},
new GameAction("offbeatSwitch", "Switch to Offbeat")
{
preFunction = delegate { var e = eventCaller.currentEntity; Lockstep.OffbeatSwitchSound(e.beat, e["ho"], e["sound"]); },
defaultLength = 4.5f,
parameters = new List<Param>()
{
new Param("sound", true, "Sound Cue"),
new Param("ho", true, "Ho Sounds", "Will the <ho, ho, ho, ho> sound be present?"),
new Param("visual", true, "Background Visual")
}
},
new GameAction("onbeatSwitch", "Switch to Onbeat")
{
preFunction = delegate { var e = eventCaller.currentEntity; Lockstep.OnbeatSwitchSound(e.beat, e["hai"], e["sound"]); },
defaultLength = 3f,
parameters = new List<Param>()
{
new Param("sound", true, "Sound Cue"),
new Param("hai", new EntityTypes.Integer(0, 100, 1), "Hai Amount"),
new Param("visual", true, "Background Visual")
}
},
new GameAction("hai", "Hai")
{
preFunction = delegate { Lockstep.HaiSound(eventCaller.currentEntity.beat); }
},
new GameAction("ho", "Ho")
{
preFunction = delegate { Lockstep.HoSound(eventCaller.currentEntity.beat); }
},
new GameAction("set colours", "Set Colours")
{
function = delegate {var e = eventCaller.currentEntity; Lockstep.instance.SetBackgroundColours(e["colorA"], e["colorB"], e["objColA"], e["objColB"], e["objColC"]); },
parameters = new List<Param>()
{
new Param("colorA", Lockstep.defaultBGColorOn, "Background Onbeat", "Select the color that appears for the onbeat."),
new Param("colorB", Lockstep.defaultBGColorOff, "Background Offbeat", "Select the color that appears for the offbeat."),
new Param("objColA", Lockstep.stepperOut, "Stepper Outline", "Select the color used for the outline of the stepswitchers."),
new Param("objColB", Lockstep.stepperDark, "Stepper Dark", "Select the color that appears for the dark side of the stepwitchers."),
new Param("objColC", Lockstep.stepperLight, "Stepper Light", "Select the color that appears for the light side of the stepwitchers."),
},
defaultLength = 0.5f,
},
new GameAction("zoom", "Preset Zooms")
{
function = delegate { Lockstep.instance.SetZoom(eventCaller.currentEntity["zoom"]); },
parameters = new List<Param>()
{
new Param("zoom", Lockstep.ZoomPresets.Regular, "Zoom Level")
}
},
new GameAction("bach", "Show Bach")
{
defaultLength = 4,
resizable = true,
},
new GameAction("marching", "Force Stepping")
{
preFunction = delegate {var e = eventCaller.currentEntity; Lockstep.Marching(e.beat, e["sound"], e["amount"], e["visual"], true, e.length);},
parameters = new List<Param>()
{
new Param("sound", false, "Sound", "Hai if onbeat, ho if offbeat.", new List<Param.CollapseParam>()
{
new Param.CollapseParam((x, _) => (bool)x, new string[] { "amount" })
}),
new Param("amount", new EntityTypes.Integer(1, 50, 1), "Sound Amount", "How many sounds will play consecutively?"),
new Param("visual", true, "Background Visual")
},
preFunctionLength = 1,
resizable = true,
defaultLength = 4
}
},
new List<string>() {"ntr", "keep"},
"ntrbackbeat", "en",
new List<string>() {}
);
}
}
}
namespace HeavenStudio.Games
{
// using Scripts_Lockstep;
public class Lockstep : Minigame
{
private static Color _defaultBGColorOn;
public static Color defaultBGColorOn
{
get
{
ColorUtility.TryParseHtmlString("#f0338d", out _defaultBGColorOn);
return _defaultBGColorOn;
}
}
private static Color _defaultBGColorOff;
public static Color defaultBGColorOff
{
get
{
ColorUtility.TryParseHtmlString("#BC318B", out _defaultBGColorOff);
return _defaultBGColorOff;
}
}
private static Color _stepperDark;
public static Color stepperDark
{
get
{
ColorUtility.TryParseHtmlString("#737373", out _stepperDark);
return _stepperDark;
}
}
private static Color _stepperLight;
public static Color stepperLight
{
get
{
ColorUtility.TryParseHtmlString("#FFFFFF", out _stepperLight);
return _stepperLight;
}
}
private static Color _stepperOut;
public static Color stepperOut
{
get
{
ColorUtility.TryParseHtmlString("#9A2760", out _stepperOut);
return _stepperOut;
}
}
public Color currentBGOnColor;
public Color currentBGOffColor;
[Header("Components")]
[SerializeField] Animator stepswitcherPlayer;
[SerializeField] Animator stepswitcherLeft;
[SerializeField] Animator stepswitcherRight;
[SerializeField] Animator bach;
// master stepper dictates what sprite the slave steppers use
[SerializeField] Animator masterStepperAnim;
[SerializeField] SpriteRenderer masterStepperSprite;
// slave steppers copy the sprite of the master stepper
[SerializeField] SpriteRenderer[] slaveSteppers;
// rendertextures update when the slave steppers change sprites
[SerializeField] Vector2 rtSize;
[SerializeField] Camera cameraNear1, cameraNear2, cameraDV;
[SerializeField] RawImage topT, topN, bottomL, bottomC, bottomR, bottomN;
[SerializeField] SpriteRenderer background;
[SerializeField] Material stepperMaterial;
[Header("Properties")]
static List<QueuedMarch> queuedInputs = new();
RenderTexture[] renderTextures;
Sprite masterSprite;
HowMissed currentMissStage;
bool lessSteppers = false;
public enum HowMissed
{
NotMissed = 0,
MissedOff = 1,
MissedOn = 2
}
bool offColorActive;
bool goBop;
public GameEvent bop = new GameEvent();
List<double> switches = new();
private List<RiqEntity> bachEvents = new();
public static Lockstep instance;
public enum ZoomPresets
{
Regular,
NotThatFar,
Far,
VeryFar,
ExtremelyFar
}
void Awake()
{
instance = this;
currentBGOnColor = defaultBGColorOn;
currentBGOffColor = defaultBGColorOff;
var switchEvents = EventCaller.GetAllInGameManagerList("lockstep", new string[] { "onbeatSwitch", "offbeatSwitch" });
foreach (var switchEvent in switchEvents)
{
switches.Add(switchEvent.beat + switchEvent.length - 1);
}
bachEvents = EventCaller.GetAllInGameManagerList("lockstep", new string[] { "bach" });
renderTextures = new RenderTexture[3];
renderTextures[0] = new RenderTexture((int)rtSize.x, (int)rtSize.y, 24, RenderTextureFormat.ARGB32)
{
wrapMode = TextureWrapMode.Repeat,
};
renderTextures[1] = new RenderTexture((int)rtSize.x, (int)rtSize.y, 24, RenderTextureFormat.ARGB32)
{
wrapMode = TextureWrapMode.Repeat,
};
renderTextures[2] = new RenderTexture((int)rtSize.x, (int)rtSize.y, 24, RenderTextureFormat.ARGB32)
{
wrapMode = TextureWrapMode.Repeat,
};
cameraNear1.targetTexture = renderTextures[0];
cameraNear2.targetTexture = renderTextures[1];
cameraDV.targetTexture = renderTextures[2];
topT.texture = renderTextures[2];
topN.texture = renderTextures[0];
bottomL.texture = renderTextures[2];
bottomC.texture = renderTextures[2];
bottomR.texture = renderTextures[2];
bottomN.texture = renderTextures[1];
}
void OnDestroy()
{
foreach (var rt in renderTextures)
{
rt.Release();
}
}
private static bool ForceStepOnBeat(double beat)
{
return EventCaller.GetAllInGameManagerList("lockstep", new string[] { "marching" }).Find(x => beat >= x.beat && beat < x.beat + x.length) != null;
}
private void PersistColors(double beat)
{
var allEventsBeforeBeat = EventCaller.GetAllInGameManagerList("lockstep", new string[] { "" }).FindAll(x => x.beat < beat);
if (allEventsBeforeBeat.Count > 0)
{
allEventsBeforeBeat.Sort((x, y) => x.beat.CompareTo(y.beat));
var lastEvent = allEventsBeforeBeat[^1];
SetBackgroundColours(lastEvent["colorA"], lastEvent["colorB"], lastEvent["objColA"], lastEvent["objColB"], lastEvent["objColC"]);
}
}
private bool BachOnBeat(double beat)
{
return bachEvents.Find(x => beat >= x.beat && beat < x.beat + x.length) != null;
}
public override void OnGameSwitch(double beat)
{
QueueSwitchBGs(beat);
PersistColors(beat);
}
public override void OnPlay(double beat)
{
QueueSwitchBGs(beat);
PersistColors(beat);
}
private void QueueSwitchBGs(double beat)
{
double nextGameSwitchBeat = double.MaxValue;
List<RiqEntity> allEnds = EventCaller.GetAllInGameManagerList("gameManager", new string[] { "switchGame", "end" }).FindAll(x => x.beat > beat);
if (allEnds.Count > 0)
{
nextGameSwitchBeat = allEnds[0].beat;
}
var switchEventsOn = EventCaller.GetAllInGameManagerList("lockstep", new string[] { "onbeatSwitch" });
foreach (var on in switchEventsOn)
{
if (on.beat >= nextGameSwitchBeat) continue;
OnbeatSwitch(on.beat, beat, on["visual"]);
}
var switchEventsOff = EventCaller.GetAllInGameManagerList("lockstep", new string[] { "offbeatSwitch" });
foreach (var off in switchEventsOff)
{
if (off.beat >= nextGameSwitchBeat) continue;
OffbeatSwitch(off.beat, beat, off["visual"]);
}
}
void Start() {
stepperMaterial.SetColor("_ColorAlpha", stepperOut);
stepperMaterial.SetColor("_ColorBravo", stepperDark);
stepperMaterial.SetColor("_ColorDelta", stepperLight);
masterSprite = masterStepperSprite.sprite;
stepswitcherLeft.gameObject.SetActive(lessSteppers);
stepswitcherRight.gameObject.SetActive(lessSteppers);
masterStepperAnim.gameObject.SetActive(!lessSteppers);
UpdateAndRenderSlaves();
cameraNear1.Render();
cameraNear2.Render();
cameraDV.Render();
}
void UpdateAndRenderSlaves()
{
foreach (var stepper in slaveSteppers)
{
stepper.sprite = masterSprite;
}
}
void PlayStepperAnim(string animName, bool player, float timescale = 1f, float startpos = 0f, int layer = -1)
{
if (player) stepswitcherPlayer.DoScaledAnimationAsync(animName, timescale, startpos, layer);
if (lessSteppers)
{
stepswitcherLeft.DoScaledAnimationAsync(animName, timescale, startpos, layer);
stepswitcherRight.DoScaledAnimationAsync(animName, timescale, startpos, layer);
}
else
{
masterStepperAnim.DoScaledAnimationAsync(animName, timescale, startpos, layer);
}
}
public override void OnBeatPulse(double beat)
{
if (goBop)
{
PlayStepperAnim("Bop", true, 0.5f);
}
}
private void Update()
{
var cond = Conductor.instance;
if (cond.isPlaying && !cond.isPaused)
{
if (queuedInputs.Count > 0)
{
foreach (var input in queuedInputs)
{
if (input.force)
{
ForceMarching(input.beat, input.length, input.sound, input.amount, input.visual);
}
else
{
StartMarching(input.beat, input.sound, input.amount, input.visual);
}
}
queuedInputs.Clear();
}
if (PlayerInput.GetIsAction(InputAction_BasicPress) && !IsExpectingInputNow(InputAction_BasicPress))
{
currentMissStage = HowMissed.NotMissed;
double beatAnimCheck = cond.songPositionInBeatsAsDouble - 0.25;
if (beatAnimCheck % 1.0 >= 0.5)
{
stepswitcherPlayer.DoScaledAnimationAsync("OnbeatMarch", 0.5f);
}
else
{
stepswitcherPlayer.DoScaledAnimationAsync("OffbeatMarch", 0.5f);
}
SoundByte.PlayOneShot("miss");
ScoreMiss();
}
}
}
private void LateUpdate()
{
if (masterSprite != masterStepperSprite.sprite)
{
masterSprite = masterStepperSprite.sprite;
UpdateAndRenderSlaves();
}
}
public void SetZoom(int zoom)
{
GameCamera.AdditionalPosition = new Vector3(0, 0, (ZoomPresets)zoom switch
{
ZoomPresets.Regular => 0,
ZoomPresets.NotThatFar => -4.5f,
ZoomPresets.Far => -11,
ZoomPresets.VeryFar => -26,
ZoomPresets.ExtremelyFar => -63,
_ => throw new System.NotImplementedException()
});
}
public void Bop(double beat, float length, bool shouldBop, bool autoBop)
{
goBop = autoBop;
if (shouldBop)
{
for (int i = 0; i < length; i++)
{
BeatAction.New(instance, new List<BeatAction.Action>()
{
new BeatAction.Action(beat + i, delegate
{
PlayStepperAnim("Bop", true, 0.5f);
})
});
}
}
}
public static void HaiSound(double beat)
{
SoundByte.PlayOneShot("games/lockstep/hai", beat, 1, 1, false, null, 0.02314814814f);
}
public static void HoSound(double beat)
{
SoundByte.PlayOneShot("games/lockstep/ho", beat, 1, 1, false, null, 0.03086419753);
}
public static void OnbeatSwitchSound(double beat, int hais, bool sound)
{
if (sound)
{
MultiSound.Play(new MultiSound.Sound[]
{
new MultiSound.Sound("lockstep/nha1", beat, 1, 1, false, 0.03086419753),
new MultiSound.Sound("lockstep/nha2", beat + 0.5f, 1, 1, false, 0.04629629629),
new MultiSound.Sound("lockstep/nha1", beat + 1f, 1, 1, false, 0.03086419753),
new MultiSound.Sound("lockstep/nha2", beat + 1.5f, 1, 1, false, 0.04629629629)
}, forcePlay: true);
}
if (hais > 0)
{
List<MultiSound.Sound> haisList = new();
for (int i = 0; i < hais; i++)
{
haisList.Add(new MultiSound.Sound("lockstep/hai", beat + 2 + i, 1, 1, false, 0.02314814814));
}
double nextOffBeat = double.MaxValue;
var switchEventsOn = EventCaller.GetAllInGameManagerList("lockstep", new string[] { "offbeatSwitch" });
switchEventsOn.Sort((x, y) => x.beat.CompareTo(y.beat));
for (int i = 0; i < switchEventsOn.Count; i++)
{
if (switchEventsOn[i].beat > beat)
{
nextOffBeat = switchEventsOn[i].beat;
break;
}
}
var haisActual = haisList.FindAll(x => x.beat < nextOffBeat);
MultiSound.Play(haisActual.ToArray(), true, true);
}
}
private void OnbeatSwitch(double beat, double gameswitchBeat, bool visual)
{
List<BeatAction.Action> allActions = new List<BeatAction.Action>()
{
new BeatAction.Action(beat, delegate { if(visual) ChangeBeatBackGroundColour(false); }),
new BeatAction.Action(beat + 0.5f, delegate { if (visual) ChangeBeatBackGroundColour(true); }),
new BeatAction.Action(beat + 1f, delegate
{
if(visual) ChangeBeatBackGroundColour(false);
}),
new BeatAction.Action(beat + 1.5f, delegate
{
if (visual) ChangeBeatBackGroundColour(true);
}),
new BeatAction.Action(beat + 1.75f, delegate { if (!marchRecursing && !ForceStepOnBeat(beat + 2f)) MarchRecursive(beat + 2f); }),
new BeatAction.Action(beat + 2f, delegate { if (visual) ChangeBeatBackGroundColour(false); }),
};
List<BeatAction.Action> actions = new();
foreach (var action in allActions)
{
if (action.beat >= gameswitchBeat) actions.Add(action);
}
if (actions.Count > 0) BeatAction.New(instance, actions);
}
public static void OffbeatSwitchSound(double beat, bool hoSound, bool sound)
{
if (sound)
{
MultiSound.Play(new MultiSound.Sound[]
{
new MultiSound.Sound("lockstep/hai", beat, 1, 1, false, 0.02314814814),
new MultiSound.Sound("lockstep/hai", beat + 1f, 1, 1, false, 0.02314814814),
new MultiSound.Sound("lockstep/hai", beat + 2f, 1, 1, false, 0.02314814814),
new MultiSound.Sound("lockstep/hahai1", beat + 3f, 1, 1, false, 0.03086419753),
new MultiSound.Sound("lockstep/hahai2", beat + 3.5f, 1, 1, false, 0.03086419753),
}, forcePlay: true);
}
if (hoSound)
{
List<MultiSound.Sound> hos = new List<MultiSound.Sound>
{
new MultiSound.Sound("lockstep/ho", beat + 4.5f, 1, 1, false, 0.03086419753),
new MultiSound.Sound("lockstep/ho", beat + 5.5f, 1, 0.6835514f, false, 0.03086419753),
new MultiSound.Sound("lockstep/ho", beat + 6.5f, 1, 0.3395127f, false, 0.03086419753),
new MultiSound.Sound("lockstep/ho", beat + 7.5f, 1, 0.1200322f, false, 0.03086419753),
};
double nextOnBeat = double.MaxValue;
var switchEventsOn = EventCaller.GetAllInGameManagerList("lockstep", new string[] { "onbeatSwitch" });
switchEventsOn.Sort((x, y) => x.beat.CompareTo(y.beat));
for (int i = 0; i < switchEventsOn.Count; i++)
{
if (switchEventsOn[i].beat > beat)
{
nextOnBeat = switchEventsOn[i].beat;
break;
}
}
var hosActual = hos.FindAll(x => x.beat < nextOnBeat);
MultiSound.Play(hosActual.ToArray(), true, true);
}
}
private void OffbeatSwitch(double beat, double gameswitchBeat, bool visual)
{
List<BeatAction.Action> allActions = new List<BeatAction.Action>()
{
new BeatAction.Action(beat, delegate { if (visual) ChangeBeatBackGroundColour(true); }),
new BeatAction.Action(beat + 1f, delegate { if (visual) ChangeBeatBackGroundColour(false); }),
new BeatAction.Action(beat + 2f, delegate { if (visual) ChangeBeatBackGroundColour(true); }),
new BeatAction.Action(beat + 3f, delegate
{
if (visual) ChangeBeatBackGroundColour(false);
}),
new BeatAction.Action(beat + 3.25f, delegate { if (!marchRecursing && !ForceStepOnBeat(beat + 3.5)) MarchRecursive(beat + 3.5f); }),
new BeatAction.Action(beat + 3.5f, delegate { if (visual) ChangeBeatBackGroundColour(true); }),
};
List<BeatAction.Action> actions = new();
foreach (var action in allActions)
{
if (action.beat >= gameswitchBeat) actions.Add(action);
}
if (actions.Count > 0) BeatAction.New(instance, actions);
}
private struct QueuedMarch
{
public double beat;
public float length;
public bool sound;
public int amount;
public bool visual;
public bool force;
}
public static void Marching(double beat, bool sound, int amount, bool visual, bool force = false, float length = 0)
{
if (GameManager.instance.currentGame == "lockstep")
{
if (force)
{
instance.ForceMarching(beat, length, sound, amount, visual);
}
else
{
instance.StartMarching(beat, sound, amount, visual);
}
}
else
{
queuedInputs.Add(new QueuedMarch
{
amount = amount,
beat = beat,
sound = sound,
visual = visual,
length = length,
force = force
});
}
}
private void ForceMarching(double beat, float length, bool sound, int amount, bool visual)
{
bool offBeat = beat % 1 != 0;
if (sound)
{
MultiSound.Sound[] sounds = new MultiSound.Sound[amount];
for (int i = 0; i < amount; i++)
{
sounds[i] = new MultiSound.Sound($"lockstep/" + (offBeat ? "ho" : "hai"), beat + i, 1, 1, false, offBeat ? 0.03086419753 : 0.02314814814);
}
MultiSound.Play(sounds, true, true);
}
List<BeatAction.Action> steps = new()
{
new BeatAction.Action(beat, delegate
{
if (visual) ChangeBeatBackGroundColour(offBeat);
if (BachOnBeat(beat)) bach.DoScaledAnimationAsync(offBeat ? "BachOff" : "BachOn", 0.5f);
EvaluateMarch(offBeat);
})
};
ScheduleInput(beat - 1, 1, InputAction_BasicPress, offBeat ? JustOff : JustOn, offBeat ? MissOff : MissOn, Nothing);
for (int i = 1; i < length; i++)
{
double stepBeat = beat + i;
steps.Add(new BeatAction.Action(stepBeat, delegate
{
if (BachOnBeat(stepBeat)) bach.DoScaledAnimationAsync(offBeat ? "BachOff" : "BachOn", 0.5f);
EvaluateMarch(offBeat);
}));
ScheduleInput(stepBeat - 1, 1, InputAction_BasicPress, offBeat ? JustOff : JustOn, offBeat ? MissOff : MissOn, Nothing);
}
BeatAction.New(this, steps);
}
private void StartMarching(double beat, bool sound, int amount, bool visual)
{
if (marchRecursing) return;
bool offBeat = beat % 1 != 0;
if (visual)
{
BeatAction.New(instance, new List<BeatAction.Action>()
{
new BeatAction.Action(beat, delegate { ChangeBeatBackGroundColour(offBeat); })
});
}
if (sound)
{
MultiSound.Sound[] sounds = new MultiSound.Sound[amount];
for (int i = 0; i < amount; i++)
{
sounds[i] = new MultiSound.Sound($"lockstep/" + (offBeat ? "ho" : "hai"), beat + i, 1, 1, false, offBeat ? 0.03086419753 : 0.02314814814);
}
MultiSound.Play(sounds, true, true);
}
MarchRecursive(beat);
}
private bool marchRecursing;
private void MarchRecursive(double beat)
{
marchRecursing = true;
if (NextStepIsSwitch(beat)) beat -= 0.5;
bool offBeat = beat % 1 != 0;
bool bachOnBeat = BachOnBeat(beat);
ScheduleInput(beat - 1, 1, InputAction_BasicPress, offBeat ? JustOff : JustOn, offBeat ? MissOff : MissOn, Nothing);
BeatAction.New(instance, new List<BeatAction.Action>()
{
new BeatAction.Action(beat, delegate
{
EvaluateMarch(offBeat);
MarchRecursive(beat + 1);
if (bachOnBeat) bach.DoScaledAnimationAsync(offBeat ? "BachOff" : "BachOn", 0.5f);
}),
});
}
private bool NextStepIsSwitch(double beat)
{
return switches.Contains(beat - 0.5);
}
public void EvaluateMarch(bool offBeat)
{
if (offBeat)
{
PlayStepperAnim("OffbeatMarch", false, 0.5f);
}
else
{
PlayStepperAnim("OnbeatMarch", false, 0.5f);
}
}
private void JustOn(PlayerActionEvent caller, float state)
{
currentMissStage = HowMissed.NotMissed;
stepswitcherPlayer?.DoScaledAnimationAsync("OnbeatMarch", 0.5f);
if (state >= 1f || state <= -1f)
{
SoundByte.PlayOneShot("nearMiss");
return;
}
SoundByte.PlayOneShotGame($"lockstep/foot{UnityEngine.Random.Range(1, 3)}");
SoundByte.PlayOneShotGame("lockstep/drumOn");
}
private void JustOff(PlayerActionEvent caller, float state)
{
currentMissStage = HowMissed.NotMissed;
stepswitcherPlayer?.DoScaledAnimationAsync("OffbeatMarch", 0.5f);
if (state >= 1f || state <= -1f)
{
SoundByte.PlayOneShot("nearMiss");
return;
}
SoundByte.PlayOneShotGame($"lockstep/foot{UnityEngine.Random.Range(1, 3)}");
SoundByte.PlayOneShotGame("lockstep/drumOff");
}
private void MissOn(PlayerActionEvent caller)
{
if (currentMissStage == HowMissed.MissedOn) return;
stepswitcherPlayer?.Play("OnbeatMiss", 0, 0);
SoundByte.PlayOneShotGame("lockstep/wayOff");
currentMissStage = HowMissed.MissedOn;
}
private void MissOff(PlayerActionEvent caller)
{
if (currentMissStage == HowMissed.MissedOff) return;
stepswitcherPlayer?.Play("OffbeatMiss", 0, 0);
SoundByte.PlayOneShotGame("lockstep/wayOff");
currentMissStage = HowMissed.MissedOff;
}
public void ChangeBeatBackGroundColour(bool off)
{
if (off)
{
background.color = currentBGOffColor;
offColorActive = true;
}
else
{
background.color = currentBGOnColor;
offColorActive = false;
}
}
public void SetBackgroundColours(Color onColor, Color offColor, Color outlineColor, Color darkColor, Color lightColor)
{
currentBGOnColor = onColor;
currentBGOffColor = offColor;
if (offColorActive)
{
background.color = currentBGOffColor;
}
else
{
background.color = currentBGOnColor;
}
stepperMaterial.SetColor("_ColorAlpha", outlineColor);
stepperMaterial.SetColor("_ColorBravo", darkColor);
stepperMaterial.SetColor("_ColorDelta", lightColor);
}
public void Nothing(PlayerActionEvent caller) {}
}
}