HeavenStudio/Assets/Scripts/Games/ClappyTrio/ClappyTrio.cs
minenice55 3002e48350
Alternate Control Styles Support (#554)
* add mouse controller

* support different control styles in options

deprecate old input check methods

* fully functional input actions system

* btsds InputAction

* blue bear InputAction

* more games

fix bugs with some input related systems

* coin toss re-toss

* cheer readers touch

* dog ninja touch

* multiple games

* last of the easy games' touch

* more specialized games

* specialized games 2

* finish ktb games

* remove legacy settings disclaimer

* "only" two games left

* karate man touch

* rockers touch

still needs fixes and bad judge strum

* DSGuy flicking animation

* playstyle chart property

* improve performance of minigame preloading

* improve look of cursor

make assetbundles use chunk-based compression
refactor assetbundle loading methods a bit

* prime conductor stream playback to stabilize seeking operations

* fix air rally swing on pad release

* use virtual mouse pointer

* add UniTask

* make BeatAction use UniTask

* implement UniTask to replace some coroutines

* add touch style UI elements and effects

games now support the ability to define two cursor colours if they need split screen touch inputs

* update plugins and buildscript

* implement thresholded pointer position clipping

* fix clamping

* instant show / hide

fix discord game SDK crashes
2023-10-29 19:44:47 +00:00

331 lines
12 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
using HeavenStudio.Util;
using Jukebox;
using Jukebox.Legacy;
namespace HeavenStudio.Games.Loaders
{
using static Minigames;
public static class AgbClapLoader
{
public static Minigame AddGame(EventCaller eventCaller) {
return new Minigame("clappyTrio", "The Clappy Trio", "deffff", false, false, new List<GameAction>()
{
new GameAction("clap", "Clap")
{
function = delegate { ClappyTrio.instance.Clap(eventCaller.currentEntity.beat, eventCaller.currentEntity.length, eventCaller.currentEntity.beat); },
resizable = true
},
new GameAction("bop", "Bop")
{
function = delegate { var e = eventCaller.currentEntity; ClappyTrio.instance.BopToggle(e.beat, e.length, e["bop"], e["autoBop"], e["emo"]); },
resizable = true,
parameters = new List<Param>()
{
new Param("bop", true, "Bop", "Should the lions bop?"),
new Param("autoBop", false, "Bop (Auto)", "Should the lions auto bop?"),
new Param("emo", false, "Disable Emotion", "Should the lions just show the neutral face while bopping?")
}
},
new GameAction("prepare", "Prepare Stance")
{
function = delegate { ClappyTrio.instance.Prepare(eventCaller.currentEntity["toggle"] ? 3 : 0); },
parameters = new List<Param>()
{
new Param("toggle", false, "Alt", "Whether or not the alternate version should be played")
}
},
new GameAction("sign", "Sign Enter")
{
function = delegate { var e = eventCaller.currentEntity; ClappyTrio.instance.Sign(e.beat, e.length, e["ease"], e["down"]); },
parameters = new List<Param>()
{
new Param("ease", Util.EasingFunction.Ease.Linear, "Ease", "Which ease should the sign move with?"),
new Param("down", true, "Down", "Should the sign go down?")
},
resizable = true
},
new GameAction("change lion count", "Change Lion Count")
{
function = delegate { ClappyTrio.instance.ChangeLionCount((int)eventCaller.currentEntity["valA"]); },
defaultLength = 0.5f,
parameters = new List<Param>()
{
new Param("valA", new EntityTypes.Integer(3, 8, 3), "Lion Count", "The amount of lions")
}
},
// This is still here for backwards-compatibility but is hidden in the editor
new GameAction("prepare_alt", "")
{
function = delegate { ClappyTrio.instance.Prepare(3); },
hidden = true
},
},
new List<string>() {"agb", "normal"},
"agbclap", "en",
new List<string>() {}
);
}
}
}
namespace HeavenStudio.Games
{
using Scripts_ClappyTrio;
public class ClappyTrio : Minigame
{
public int lionCount = 3;
public List<GameObject> Lion;
[SerializeField] private Sprite[] faces;
private ClappyTrioPlayer ClappyTrioPlayer;
public int misses;
bool shouldBop;
bool doEmotion = true;
public int emoCounter;
public GameEvent bop = new GameEvent();
[SerializeField] Animator signAnim;
double signStartBeat;
float signLength;
Util.EasingFunction.Ease lastEase;
bool signGoDown;
public static ClappyTrio instance { get; set; }
MultiSound clapSounds = null;
CancellationTokenSource clapAction = null;
private void Awake()
{
instance = this;
clapSounds = null;
InitLions();
}
public override void OnGameSwitch(double beat)
{
InitClaps(beat);
}
private void InitClaps(double beat)
{
RiqEntity changeLion = GameManager.instance.Beatmap.Entities.FindLast(c => c.datamodel == "clappyTrio/change lion count" && c.beat <= beat);
if (changeLion != null)
{
EventCaller.instance.CallEvent(changeLion, true);
}
var allClaps = EventCaller.GetAllInGameManagerList("clappyTrio", new string[] { "clap" });
foreach (var c in allClaps)
{
if (c.beat < beat && c.beat + (c.length * (lionCount - 1)) >= beat)
{
Clap(c.beat, c.length, beat);
}
}
}
void Update()
{
var cond = Conductor.instance;
if (cond.ReportBeat(ref bop.lastReportedBeat, bop.startBeat % 1))
{
if (shouldBop) Bop(cond.songPositionInBeatsAsDouble);
}
if (cond.isPlaying && !cond.isPaused)
{
float normalizedBeat = cond.GetPositionFromBeat(signStartBeat, signLength);
if (normalizedBeat > 0 && normalizedBeat <= 1)
{
Util.EasingFunction.Function func = Util.EasingFunction.GetEasingFunction(lastEase);
float newPos = func(0, 1, normalizedBeat);
signAnim.DoNormalizedAnimation(signGoDown ? "Enter" : "Exit", newPos);
}
}
}
public void Sign(double beat, float length, int ease, bool down)
{
SoundByte.PlayOneShotGame("clappyTrio/sign");
signStartBeat = beat;
signLength = length;
lastEase = (Util.EasingFunction.Ease)ease;
signGoDown = down;
}
private void InitLions()
{
float startPos = -3.066667f;
float maxWidth = 12.266668f;
for (int i = 0; i < lionCount; i++)
{
GameObject lion;
if (i == 0)
lion = Lion[0];
else
lion = Instantiate(Lion[0], Lion[0].transform.parent);
lion.transform.localPosition = new Vector3(startPos + ((maxWidth / (lionCount + 1)) * (i + 1)), 0);
if (i > 0)
Lion.Add(lion);
if (i == lionCount - 1)
ClappyTrioPlayer = lion.AddComponent<ClappyTrioPlayer>();
}
if (clapSounds != null)
clapSounds.Delete();
if (clapAction != null)
{
clapAction.Cancel();
clapAction.Dispose();
}
}
public void Clap(double beat, float length, double gameSwitchBeat)
{
ClappyTrioPlayer.clapStarted = true;
ClappyTrioPlayer.canHit = true; // this is technically a lie, this just restores the ability to hit
// makes the other lions clap
List<MultiSound.Sound> sounds = new List<MultiSound.Sound>();
List<BeatAction.Action> actions = new List<BeatAction.Action>();
for (int i = 0; i < Lion.Count - 1; i++)
{
bool isBeforeGameSwitch = beat + (length * i) < gameSwitchBeat;
int idx = i;
if (isBeforeGameSwitch)
{
SetFace(idx, 4);
Lion[idx].GetComponent<Animator>().Play("Clap", 0, 1);
}
else
{
sounds.Add(new MultiSound.Sound((i > 0) ? "clappyTrio/middleClap" : "clappyTrio/leftClap", beat + (length * i)));
actions.Add(new BeatAction.Action(beat + (length * i), delegate
{ SetFace(idx, 4); Lion[idx].GetComponent<Animator>().Play("Clap", 0, 0); }));
}
}
if (sounds.Count > 0) clapSounds = MultiSound.Play(sounds.ToArray());
if (actions.Count > 0) clapAction = BeatAction.New(this, actions);
// prepare player input
ClappyTrioPlayer.QueueClap(beat, length * (Lion.Count - 1));
}
public void Prepare(int type)
{
for (int i = 0; i < Lion.Count; i++)
{
SetFace(i, type);
}
PlayAnimationAll("Prepare");
SoundByte.PlayOneShotGame("clappyTrio/ready");
}
public void BopToggle(double beat, float length, bool startBop, bool autoBop, bool emo)
{
doEmotion = !emo;
shouldBop = autoBop;
if (startBop)
{
List<BeatAction.Action> bops = new List<BeatAction.Action>();
for (int i = 0; i < length; i++)
{
if (i == 0 && startBop && autoBop) continue;
double spawnBeat = beat + i;
bops.Add(new BeatAction.Action(spawnBeat, delegate { Bop(spawnBeat); }));
if (i == length - 1)
{
bops.Add(new BeatAction.Action(spawnBeat, delegate { misses = 0; }));
}
}
if (bops.Count > 0) BeatAction.New(instance, bops);
}
}
public void Bop(double beat)
{
if (doEmotion && emoCounter > 0)
{
if (misses == 0)
{
for (int i = 0; i < Lion.Count; i++)
{
SetFace(i, 1);
}
}
else if (misses > 0)
{
var a = EventCaller.GetAllInGameManagerList("clappyTrio", new string[] { "clap" });
var b = a.FindAll(c => c.beat < beat);
if (b.Count > 0)
{
for (int i = 0; i < Lion.Count; i++)
{
if (i == Lion.Count - 1)
{
SetFace(i, 0);
}
else
{
SetFace(i, 2);
}
}
}
}
emoCounter--;
}
else
{
for (int i = 0; i < Lion.Count; i++)
{
SetFace(i, 0);
}
}
PlayAnimationAll("Bop");
}
public void ChangeLionCount(int lions)
{
for(int i=1; i<lionCount; i++)
{
Destroy(Lion[i]);
}
Lion.RemoveRange(1, lionCount - 1);
lionCount = lions;
SetFace(0, 0);
InitLions();
PlayAnimationAll("Idle");
}
private void PlayAnimationAll(string anim)
{
for (int i = 0; i < Lion.Count; i++)
{
Lion[i].GetComponent<Animator>().Play(anim, -1, 0);
}
}
public void SetFace(int lion, int type)
{
Lion[lion].transform.GetChild(1).GetComponent<SpriteRenderer>().sprite = faces[type];
}
}
}